As mentioned when discussing how Node does path lookups, modules may be contained within a folder. If you are developing a program as a module for others to use you should bundle that module within its own folder and publish it. The npm package management system is designed to help you do just that.
As we've seen throughout the examples in this book, a package.json
file describes a module, usefully documenting the module's name, version number, dependencies, and so forth. It must exist if you would like to publish your package via npm. In this section we will investigate the key properties of this file, and offer some hints and tips on how to configure and distribute your modules.
Note
Try npm help json
to fetch detailed documentation for all the available package.json
fields, or visit https://npmjs.org/doc/json.html.
A package.json
file must conform to the JSON specification. For example, properties and values must be double-quoted.
You can create a package file by hand, or use the handy npm init
command-line tool, which will prompt you for a series of values and automatically generate a package.json
file. Let's run through some of these values:
name: (Required) This string is what will be passed to
require()
in order to load your module. Make it short and descriptive, using only alphanumeric characters—this name will be used in URLs, command line arguments, and folder names. Try to avoid using "js" or "node" in the name.version: (Required) npm uses semantic versioning, where these are all valid:
>=1.0.2 <2.1.2
2.1.x
~1.2
Note
For more information on version numbers, visit https://npmjs.org/doc/misc/semver.html.
description: When people search npmjs.org for packages, this is what they will read. Make it short and descriptive.
entry point: This is the file that should set
module.exports
—it defines where the module object definition resides.keywords: A comma-separated list of keywords that will help others find your module in the registry.
license: Node is an open community that likes permissive licenses. "MIT" and "BSD" are good ones here.
You might also want to set the private
field to true
while you are developing your module. This ensures that npm will refuse to publish it, avoiding accidental releases of incomplete or time-sensitive code.
npm is ultimately a build tool, and the scripts
field in your package file allows you to set various build directives executed at some point following certain npm
commands. For example, you might want to minify JavaScript, or execute some other processes that build dependencies that your module will need whenever npm install
is executed. The available directives are:
prepublish, publish, postpublish: Run by the
npm publish
command.preinstall, install, postinstall: Run by the
npm install
command.preuninstall, uninstall, postuninstall: Run by the
npm uninstall
command.preupdate, update, postupdate: Run by the
npm update
command.prerestart, restart, postrestart: Run by the
npm restart
command. Note thatnpm restart
will run thestop
andstart
scripts if norestart
script is provided.
It should be clear that the commands with prefix pre will run before, and the commands with prefix post will run after their primary command (such as publish
) is executed.
Note
Package files demonstrating the use of script directives can be found in the mocha-zombie
folder in the code bundle for Chapter 9, Testing Your Application.
It is likely that a given module will itself depend on other modules. These dependencies are declared within a package.json
file using four related properties, which are:
dependencies: The core dependencies of your module should reside here.
devDependencies: Some modules are only needed during development (and not in production), such as those used for testing. Declare those modules here.
bundledDependencies: Node is changing rapidly, as are npm packages. You may want to lock a certain bundle of dependencies into a single bundled file and have those published with your package, such that they will not change via the normal
npm update
process.optionalDependencies: Contains modules that are optional. If these modules cannot be found or installed the build process will not stop (as it will with other dependency load failures). You can then check for this module's existence in your application code.
Dependencies are normally defined with a npm package name followed by versioning information:
"dependencies" : { "express" : "3.3.5" }
However they can also point to a tarball:
"foo" : "http://foo.com/foo.tar.gz"
You can point to a GitHub repository:
"herder": "git://github.com/sandro-pasquali/herder.git#master"
Or even the shortcut:
"herder": "sandro-pasquali/herder"
Note
These GitHub paths are also available to npm install
. For example, npm install sandro-pasquali/herder
.
Additionally, in cases where only those with proper authentication are able to install a module, the following format can be used to source secure repositories:
"dependencies": { "a-private-repo": "git+ssh://[email protected]:user/repo.git#master" }
By properly organizing your dependencies by type, and intelligently sourcing those dependencies, build requirements should be easy to accommodate using Node's package system.
In order to publish to npm, you will need to create a user. npm adduser
will trigger a series of prompts requesting your name, e-mail, and password. You may then use this command on multiple machines to authorize the same user account.
Note
To reset your npm password visit https://npmjs.org/forgot.
Once you have authenticated with npm you will be able to publish your packages using the command npm publish
. The easiest path is to run this command from your package folder. You may also target another folder for publishing (remember that a package.json
file must exist in that folder).
You may also publish a gzipped TAR archive containing a properly configured package folder.
Note that if the version
field of the current package.json
file is lower or equal to that of the existing, published package npm will complain and refuse to publish. You can override this by using the --force
argument with publish
, but you probably want to update the version and republish.
To remove a package use npm unpublish <name>[@<version>]
. Note that once a package is published other developers may depend on it. For this reason you are strongly discouraged from removing packages that others are using. If what you want to do is discourage the use of a version, use npm deprecate <name>[@<version>] <message>
.
To further assist collaboration, npm allows multiple owners to be set for a package:
npm owner ls <package name>
: Lists the users with access to a module.npm owner add <user> <package name>
: The added owner will have full access, including the ability to modify the package and add other owners.npm owner rm <user> <package name>
: Removes an owner and immediately revokes all privileges.
All owners have equal privileges—special access controls are unavailable, such as being able to give write but not delete access.
Some Node modules are useful as command-line programs. Rather than requiring something such as > node module.js
to run a program, we might want to simply type > module
on the console and have the program execute. In other words, we might want to treat a module as an executable file installed on the system $PATH
and therefore accessible from anywhere. There are two ways to achieve this using npm.
The first and simplest way is to install a package using the -g (global)
argument:
npm install -g module
If a package is intended as a command-line application that should be installed globally, it is a good idea to set the
preferGlobal
property of your package.json
file to true
. The module will still install locally, but users will be warned about its global intentions.
Another way to ensure global access is by setting a package's bin
property:
"name": "aModule", "bin" : { "aModule" : "./path/to/program" }
When this module is installed, aModule
will be understood as a global CLI command. Any number of such programs may be mapped to bin
. As a shortcut, a single program can be mapped like so:
"name": "aModule", "bin" : "./path/to/program"
In this case the name of the package itself (aModule
) will be understood as the active command.
Node modules are often stored in version control systems, allowing several developers to manage package code. For this reason the repository
field of package.json
can be used to point developers to such a repository, should collaboration be desired. For example:
"repository" : { "type" : "git", "url" : "http://github.com/sandro-pasquali/herder.git" } "repository" : { "type" : "svn", "url" : "http://v8.googlecode.com/svn/trunk/" }
Similarly, you might want to point users to where bug reports should be filed by using the bugs field:
"bugs": { "url": "https://github.com/sandro-pasquali/herder/issues" }