I’ve been spending a lot of time lately writing JavaScript, and my latent curiosity about npm has finally got the better of me
once I started writing a mocha wrapper for Douglas Crockford’s recently released JavaScript QuickCheck implementation called JSCheck. (stretch.js if you want to check it out)
I wasn’t able to find a clear reference on how to start a package from scratch. After scouring the npm docs, blog articles and some popular npm packages I was able to come up with a basic formula for creating a new npm package.
This is that formula:
Get Nodejs
If you’re on a mac
$ brew install nodejs
Otherwise visit the nodejs download page to get a version for your system.
npm init
Create a directory for your project and cd into it
$ mkdir your-project && cd your-project
Now run npm init, entering any information you choose.
npm init will gather metadata about your project and create ./package.json that npm uses as the primary location for project metadata, dependencies and execution instructions.
One option of note is “Main module/entry point”. This option (default: index.js) names the file that is initially entered when require('your-project') is called.
Flesh it out
Now that package.json is created we can start fleshing out our project. I prefer to keep index.js simple, and thus it only acts as an entry point into the rest of the project.
module.exports = require('./lib/your-project');
Application code can now live happily sequestered in ./lib. We may as well get that started now too:
$ mkdir lib
$ touch lib/your-project.js
For now lets keep your-project.js simple and fill it with something like this:
exports.version = require('../package').version;
// actual code goes here...
Test it with Mocha
We’d preferably like to be able to test our application, so lets add mocha and chai to the project.
Open up package.json and change
"devDependencies": {},
to
"devDependencies": {
"mocha": "~1.0",
"chai" : "~0.5"
},
npm supports a number of version specifiers, but in this case I just want anything less than 2.0. (The dependencies section of docs/json.html has further details.)
$ npm install
will install mocha and chai into ./node_modules. I suggest we also hide this from git
$ echo "node_modules" >> .gitignore
Add a basic test
Place the following in test/your-project.js
var mocha = require('mocha');
var expect = require('chai').expect;
describe("My project", function () {
it("should know its version", function () {
var myProject = require('../index');
expect(myProject.version).to.not.equal(undefined);
expect(myProject.version).to.equal('0.0.0');
});
});
Now if you run the command mocha test/your-project.js or, more generally, mocha, you should see:
$ mocha
.
✔ 1 test complete (2ms)
Setup a Makefile
A pattern I observed in a few npm packages was using Makefiles to manage build and test tasks. Place the following in ./Makefile
test:
./node_modules/.bin/mocha
.PHONY: test
Now you can
$ make test
to execute your test suite. Makefile’s are sensitive about whitespace. Use tabs, not spaces
Bonus: Travis CI Integration
If you want to go the extra mile, setup continuous integration on Travis. I’m not going to go into detail now, but the general steps to follow are:
- Push your-project to github
- Go to your profile page
- Turn on “your-project””
- Create a
./.travis.yml
Your .travis.yml should look like this:
language: node_js
node_js:
- 0.6
For further detail check out Travis docs > getting started.
Recap
Setup a basic project:
brew install nodejs
mkdir your-project && cd your-project
npm init
echo "module.exports = require('./lib/your-project')" >> index.js
mkdir lib
echo "exports.version = require('../package').version;" >> lib/your-project.js
Add Mocha + Chai for testing
# add mocha version ~1.0 and chai version ~0.5 to devDependencies in package.json
npm install
echo "node_modules" >> .gitignore
mkdir test
curl https://raw.github.com/gist/2552913/b42f89808c4d7b9ee6241aa83bc42ba1300e81f9/your-project-test.js > test/your-project.js
echo "test:\n\t./node_modules/.bin/mocha\n\n.PHONY: test" > Makefile
make
Optionally,
- Push to Github
- Integrate with Travis CI
Questions? Suggestions for improvement?