Your first Node.js package
This is pretty simple, let's dive in!
Has someone already written this package?
It might be worth saving yourself some time and doing a couple of searches for the package you are looking for.
As of this writing there are ~86k packages in npm and there is a good chance someone has done something similar to what you are building.
Some good places to search are: http://npmjs.org, http://node-modules.com, and http://npmsearch.com. There is also npm search
on the command-line which you may find useful.
Choose a name
Find a name that isn't taken and clearly describes what your package is doing. You'll probably not want to use your-first-node-package
as below, but for example's sake that is what we will be using.
Choose a descriptive name!
$ npm view your-first-node-package
npm ERR! 404 'your-first-node-package' is not in the npm registry.
...
Woohoo, that name is not taken, let's take it.
Project initialization
It's probably best if you create a GitHub repository before initializing your project. That way when we run npm init
, it will already know what repository you're pulling from and your git remote
will be properly setup to track origin/master.
If that was all mumbo-jumbo, then it might be wise to have the git cheatsheet on hand.
$ git clone git@github.com:user/your-first-node-package.git
$ cd your-first-node-package
OK, now we are ready to initialize package.json which will let npm know what the name of your package is as well as what dependencies it uses
$ npm init
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sane defaults.
See `npm help json` for definitive documentation on these fields
and exactly what they do.
Use `npm install <pkg> --save` afterwards to install a package and
save it as a dependency in the package.json file.
Press ^C at any time to quit.
name: (your-first-node-package)
version: (0.0.0)
description: My very first package
entry point: (index.js)
test command:
git repository: (https://github.com/user/your-first-node-package.git)
keywords:
author: Elijah Insua <tmpvar@gmail.com> (http://tmpvar.com)
license: (ISC)
About to write to /Users/tmpvar/your-first-node-package/package.json:
{
"name": "your-first-node-package",
"version": "0.0.0",
"description": "My very first package",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "https://github.com/user/your-first-node-package.git"
},
"author": "Elijah Insua <tmpvar@gmail.com> (http://tmpvar.com)",
"license": "MIT"
}
Is this ok? (yes)
npm init
will ask you a couple of questions. Once you've finished filling them out you can take a peek at the package.json file it generated to see what it actually did.
$ cat package.json
{
"name": "your-first-node-package",
"version": "0.0.0",
"description": "very first package",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "https://github.com/user/your-first-node-package.git"
},
"author": "Elijah Insua <tmpvar@gmail.com> (http://tmpvar.com)",
"license": "MIT"
}
You can also manually edit this file if you need to. A good reason to do this is if you decide that your name is not specific enough or if the name you chose has been taken by the time you are ready to publish. You might also want to add a "test"
script later on or bump the "version"
, although you can also use npm version
for that!
package.json is a config for installing packages and resolving dependencies, but there are also packages that use it to configure other aspects of your package's lifecycle.
Code time
Packages should be easy to digest and focused on the task they were created to perform.
By splitting individual units of functionality out into their own packages you are being a good Node.js citizen by allowing those who come after you to pick and choose how they want to build applications. Not only that—smaller packages allow faster iteration, focused documentation, and generally better test coverage (it is easier to test small packages)!
The Hello World package
So let's create a new file (module) index.js and make it compute the area of a rectangle. Why? Because it's a really easy demo!
index.js
module.exports = function(width, height) {
return width * height;
};
While the filename here is index.js, you could name it whatever you want. If you change it you should update package.json's "main"
property to match.
What is that module.exports
thing?
When Node.js loads your module it's actually wrapping it in a function that looks sort of like:
function(__dirname, __filename, module, exports, require) {
// ...
}
Where __dirname
and __filename
are the current directory and filename of the module being loaded.
require()
is a function that will synchronously load another package or module from the filesystem and return it. The package or module will be cached when first loaded, so subsequent calls to require()
for that package or module in your Node.js application will not need to re-read the file.
module.exports
provides a way for modules to expose functionality. Let's take a look at how this would work with our example.
Node.js REPL
If you run node
in a terminal, you will enter an interactive JavaScript prompt called the Node.js REPL (Read Eval Print Loop). We'll be using this prompt to test our new package—it goes something like this:
$ node
> var area = require('./index.js');
undefined
> area(2,4)
8
>
(^C again to quit)
>
(Hint: press Ctrl+C twice to exit the REPL.)
Because we set module.exports
to a function, it is the only thing exported. We can then call it directly!
Publish time
If you are a new user:
$ npm adduser <your username>
Follow the steps and you'll have an account that lets you publish to the npm registry!
Let's get this package out into the world!
OK, we've made a package! Let's publish it on the npm registry so anyone can use it.
$ git add package.json index.js
$ git commit -m "prepare for 1.0.0"
$ npm version 1.0.0
v1.0.0
$ git push && git push --tags
$ npm publish
And that's it!
Summary
We were able to build a function that computes the area of a rectangle and published it in the npm registry so other people could use it in their projects.
This is a very basic workflow and after you do it a couple of times it becomes ingrained in your muscle memory!
Homework
- Read through the Node.js modules documentation.
- Add tests to your package, tape or mocha are amongst the most popular test runners.
- Read about semver.