Writing a Node Module

This example assumes that you have a Github account. If you don't have one, you can get one at (suprise!) Github. It also assumes that you have installed
Node and npm. It will also simplify your life to have the github gem installed

Create the basic structure

OK, now I have an initialized repository and I need something to put in it. I like Readme Driven Development and, in that spirit, let's create a Readme.

sleep-sort works by creating a task for every number to be sorted. The task
will “sleep” n number of milliseconds and then push the number onto an array.
When all tasks are done, the array is returned sorted.

I have setup a local repository and committed our Readme. Now, I need to create our remote repository on Github. With the Github gem, this is trivial.

The above creates the remote repository, pushes the local changes, and sets up the origin. I can of course do all the above manually, but why?

Making the module

Even though this is only going to be a small module, I want to create directories for the different files I plan to use.

I created a lib dir for the source files, a test dir for the tests, and a bin dir for the shell command, sleep-sort, to go in.

Lets also create the files.

OK, the directories exists and the files exist, it's time to make the module. To do this I need to create a package.json file that contains meta-information about the module. An easy way to do this is by using npm init.

npm init guesses some of the information, so that I don't have to enter it myself. When the process is done I have a package.json file in the root directory of our project, lets add it to git and commit it.

Note that I added lib/main.js as the main file. This will be the file that is required when Node requires the module later on. I also added the test script mocha test/*.js, this script can be invoked by running npm test.

But, in order for this to work, I need to add mocha as a development dependency in package.json. And while I am at it, I will also add
should.js as a dependency. should.js
provides should-style assertions.

Install the dependencies with npm install

Try the command out, by running npm test and watch it fail since I don't have
any proper tests yet.

npm install created a directory called node_modules containing all the dependencies. I don't want to check this into source control so I add a .gitignore file.

Some Code

That was a lot of stuff without writing a single line of code. Enough of that. I'll do it TDD style and write a test first.

If I run this, npm test I get an error since I haven't implemented a module in lib/main.js. Time to do that. Since I am only going to be exporting a single function, sleepsort, from this module I will export it via module.exports, instead of exports.sleepsort.

The above code gets the first test passing. Notice that I required the function directly with require('sleepsort'), in the test above, this works because of the above mentioned export method.

Now when I have a running test, it's time to set up continuous integration.

Continuous Integration

The easiest way to do this is to use Travis-CI. I need to do three things (a more complete description can be found here)

1. Sign in to (or sign up with) Travis with my Github account

2. Go to the Travis profile page

Find my repository, sleep-sort, and turn it on. This will turn on the Travis commit hook on Github, and it will run my tests, every time I push to Github. Travis will run the command I specified in package.json under the scripts/test entry, by running npm test.

3. Add a .travis.yml

Create a .travis.yml, like this.

I'm telling Travis to run the tests with both version 0.6 (stable) and 0.7 (unstable). Then commit this file, and push it to Github.

After a while you will get an email, telling you that the tests were run successfully. Relax, enjoy the beauty of Node, of Travis, of life!

Additionaly, if you want to show off that you are a responsible citizen that uses continuous integration you can add a Travis status image
to the Readme. It looks like this:

Build Status

The Binary

Now I have everything setup with testing and CI. I have a function that can sort empty arrays, instantly :), but I don't yet have a script to run it. Let's create bin/sleep-sort

I also need to register the script as a binary in package.json. Add the following line to package.json.

And make it executable, try it, add it and commit it.

Beautiful, time for another break :)

The Rest of the Code

That was a lot of work for a function that is only able to sort an empty array. And, there is something fishy going on. That function I implemented seems very synchronous, isn't Node supposed to be asynchronous?

Well, gosh! Let me fix that right away.

First I change the test. Since the code now is going to be asynchronous I will take advantage of some nifty features of mocha. If I give the callback function of it an argument done, mocha will inject a function that I can call when the test is done. Like this:

If I hadn't called done, mocha would timeout and the test would be marked as a failure. Simple, yet powerful. With a new failing test, I update the actual code.

process.nextTick tells Node that I want the function to be called next time the loop comes around. And the test is passing again, and now I can sort an empty array asynchronously. How about that!

Commit it and push it! Then, rejoice as Travis verifies it and emails that everything is fine.

Time to add one more test, a single element array.

The test fails and I am ready to fix it. Here is a function that will pass the test.

Take an extra look at appendResult. It's a function that creates another function and returns it. The created function is the function that will be called when the timeout fires.

Now I have a function that sorts single element arrays too. Let's see if it can sort more than that. One more test.

Our test doesn't pass, I need to make sure the callback is only called when the result is complete. How do I know that it is complete? I know that if the array of the result is the same length as the input array. Here is the final function.

Now, the last thing I need to do is to update the script to use the asynchronous code. That is simple, I just give console.log as a the callback parameter to sleepsort.

Done. The program is working. I have a sorting algorithm with linear complexity working! Linear to the highest value to be sorted. :D

With this mighty fine algorithm running, I need to publish it for the world to see it. How do I do that? With npm of course.

Publishing the Module

Before I publish, I try it out locally by installing it.

It works on my machine :). It may not on yours, depending on how your path is setup. If it doesn't, you may try to install it globally with npm install -g ., then try again.

Now, when it is working, it is time to publish. If this is the first time you publish something with npm, you have to add yourself as a user before you publish.

Before I publish, I bump the version up to 1.0.0, in package.json, to show that this package is ready for production.

That is all. The source code can be found on Github, if you want to play with it yourself.

Leave a Reply

Close Menu