Skip to content

Instantly share code, notes, and snippets.

@isaacs
Created February 25, 2011 01:57
Show Gist options
  • Save isaacs/843271 to your computer and use it in GitHub Desktop.
Save isaacs/843271 to your computer and use it in GitHub Desktop.

How To Module

These are some basic steps for writing a NodeJS module.

Most of the suggestions in this document are optional. You can definitely write your program however you like, and many in the node community enjoy trying out new creative ways of doing things.

This is merely a set of patterns that noders have found to work for them and their projects.

Use Git

Most people in the node community use git for all their version control needs. It is an extremely powerful and robust tool. If you don't already use it, you should.

Don't wait until your program is "ready" before using git on it! Run git init in the root of your project folder right away, and commit your changes as you make them. It is a good habit, and can help avoid a lot of painful mishaps.

If you wish to share your program with others, then github is also a tremendously useful resource that most nodejs developers use.

A package.json File

Create a file in the root of your program named package.json. This file is a json description of what's in your project. If you're just writing a standalone server or website that isn't intended to ever be shared, then this is not strictly necessary, but it still does make some things more convenient.

If you plan to publish your program and let others install it using npm, then a package.json file is essential.

You can specify in this file:

  • Name, version, description, and keywords to describe your program.
  • A homepage where users can learn more about it.
  • Other packages that yours depends on.

If you have installed npm, then you can use the npm init command to get started. See npm help json for lots of information about everything you can put in this file.

If you are writing a program that is intended to be used by others, then the most important thing to specify in your package.json file is the main module. This is the module that is the entry point to your program.

Documenting your dependencies is really handy. It is a very polite practice if you are going to share this program with others, and it provides a lot of useful techniques if you are deploying it somewhere.

README, and other docs

Put basic entry-level documentation about your program in a README file in the root of your project.

If you enjoy the markdown format, you can write it in markdown, and save the file as README.md.

Seriously, do this! Even if you think you'll never have users, history teaches us that you'll go off and forget what this thing is for, and then come back to it and curse yourself for not documenting it even a little.

So document it. Even a little.

If you feel so inclined, it's also a great idea to put documentation in a folder called ./docs. Markdown files should end in .md and html should end in .html.

What kind of thing are you making?

Generally, node modules fall into these rough categories:

  • A binding to some C or C++ library.
  • A library of functionality to be used in other node programs, written primarily in JavaScript.
  • A command-line program.
  • A website or server or something. (That is, an implementation that you'll put on an actual server, not a framework.)

There is a lot of overlap in these categories. A thing doesn't have to be just one sort of thing.

Writing a Binding

Typically, C++ source code is put in a subdirectory of your project called ./src. C++ files usually have the extension .cc. C files usually have the extension .c.

Generally, the simplest and best approach is to put the minimum necessary effort into the C++ layer, and then make the functions "nice" by wrapping a JavaScript layer around the raw binding.

Node programs use the included node-waf program to compile. Create a wscript file with the appropriate rules in it, and then run node-waf configure build to build your module.

Use the eio thread pool to do any actions that perform synchronous I/O. Note that v8 constructs may not be used on the thread pool, so data types must be passed into the sync code blocks as eio_request structs.

See these examples to get started building a binding that leverages eio and node-waf:

Example hello-world-ish programs:

Some "real" examples:

Writing a Library

If you have a lot of JavaScript code, then the custom is to put it in the ./lib folder in your project.

Specify a main module in your package.json file. This is the module that your users will load when they do require('your-library'). This module should ideally expose all of the functionality in your library.

If you want your users to be able to load sub-modules from the "guts" of your library, then they'll need to specify the full path to them. That is a lot of work to document! It's better and more future-proof to simply specify a main module, and then, if necessary, have ways to dynamically load what they need.

For example, you might have a flip library that is a collection of widget objects, defined by files in the flip/lib/widgets/*.js files. Rather than having your users do require('flip/lib/widgets/blerg.js') to get the blerg widget, it's better to have something like: require('flip').loadWidget('blerg').

Of course, a library may also include a build step that compiles an add-on that it uses.

Writing a Command Line Program

The only feature that differentiates a command-line program from a library is the bin field in the package.json file.

When installed with npm, the bin field in a package.json file tells npm to create an executable in the PATH that runs your program.

In a nodejs script, the process.argv is an array of strings that represent the command the user started node with. The first item is always node, and the second is always your program. Generally, the arguments to your program can be retrieved via:

var args = process.argv.slice(2)

There are a variety of option parsing libraries available via npm.

The current working directory can be found by calling process.cwd(), and changed with process.chdir(newPath).

Writing a Standalone Server

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment