Chapter 8. Extending Node

The module system in Node makes it easy to create extensions to the platform. It is simple to learn and enables us to easily share reusable library code. The Node module system is based on the commonJS module specification. We’ve already used lots of modules in the previous chapters, but here we’ll study how to create our own modules. Example 8-1 shows one simple implementation.

As you can see, writing a module is as simple as attaching properties to the exports global variable. Any script that is included with require() will return its exports object. This means that everything returned from require() is in a closure, so you can use private variables in a module that are not exposed to the main scope of the program.

Node developers have created a few conventions around modules. First, it’s typical to create factory methods for a class. Although you might also expose the class itself, factory methods give us a clean way to instantiate objects. For I/O-related classes, one of the arguments is normally a callback for either the I/O being done or one of its most common aspects. For example, http.Server has a factory method called http.createServer() that takes a callback function for the request event, the most commonly used http.Server event.

Being able to make modules is great, but ultimately having a good way to distribute them and share them with the rest of your team or the community is essential. The package manager for Node, npm, provides a way of distributing code, either locally or via a global repository of Node modules. npm helps you manage code dependencies, installation, and other things associated with distributing code. Best of all, npm is all JavaScript and Node. So if you are already using Node, you are ready to use npm, too. npm provides both the installation tools for developers and the distribution tools for package maintainers.

Most developers will start by using npm to install packages using the simple npm install command. You can install packages you have locally, but you’ll probably want to use npm to install remote packages from the npm registry. The registry stores packages that other Node developers make available to you to use. There are many packages in the registry: everything from database drivers to flow control libraries to math libraries. Most things you’ll install with npm are 100% JavaScript, but a few of them require compilation. Luckily, npm will do that for you. You can see what’s in the registry at http://search.npmjs.org.

Although npm excels at publishing and deploying, it was designed primarily as a tool for managing dependencies during development. The npm link command creates a symbolic link between your project and its dependencies, so any changes in the dependencies are available to you as you work on your project.

There are two major reasons you would want to do this:

Typing npm link with no arguments creates a symbolic link for the current project inside the global packages path, making it available to npm in all other projects on your system. To use this feature, you need to have a packages.json file, described earlier. Using npm init is the fastest way to generate a barebones version of this file.

Typing npm link packagename creates a symbolic link from the project’s working directory to the global modules path for that package. For example, typing npm link express will install the Express framework in the global packages directory and include it in your project. Whenever Express is updated, your project will automatically use the latest version from the global packages directory. If you have linked Express in more than one project, all of those projects will be synchronized to the most recent version, freeing you from having to update every one of them whenever Express is updated.

Whereas modules are the JavaScript extensions for Node, add-ons are the C/C++ extensions. Add-ons frequently wrap existing system libraries and expose their functionality to Node. They can, of course, create new functionality too, although most people choose to do that in JavaScript for obvious reasons. Add-ons are dynamically linked shared objects.

To create an add-on, you’ll need at least two sets of files: the add-on code and the build files. Node uses the waf build system written in Python. Let’s start with a “Hello World” example. Example 8-2 is equivalent to exports.hello = "world"; in JavaScript.

The first thing this code needs to do is include the v8 header file because Node is built on top of V8. This provides a lot of standard objects that we will use. Next, we declare the namespace. Then we create the wrapper, which is required by all add-ons. The wrapper functions like the exports global variable for JavaScript modules. We’ll hang everything we expose from the add-on off a function with the signature extern 'C' void init (Handle<Object> target).