How to Create and Publish Your First Node.js Module

Image from a very funny talk by Justin Searls about what it’s like to be an open source maintainer.

What is npm?

npm makes it easy for JavaScript developers to share and reuse code, and it makes it easy to update the code that you’re sharing. The beta of npm v3 has been released recently.

Pre-reqs

  • Sign up for a GitHub account
  • Install Node.js (npm comes with Node, but it’s often an old version)
  • Update to the latest npm version (Node’s release cycle is far slower than npm’s, which is weekly)
npm install npm@latest -g
If you get an EACCES error, don’t worry! Here's a solution.
  • Create an npm account (and confirm your npm account email address‏)
  • Create a Travis CI account (using GitHub)
  • Create a Coveralls account (using GitHub)

Create a GitHub repo

  1. Create a new repo on GitHub and call it “number-formatter” (make sure you check the README box, add a .gitignore file for Node, and a MIT license)
  2. Clone it locally
Make sure you add a README, .gitignore, and license

Note: The completed demo code is at the bottom in case you want a high-level view of the project layout.

Why add a license?

It’s your right not to include a license with your code or project, but the absence of a license means that the default copyright laws apply. This means that you retain all rights to your source code and that nobody else may reproduce, distribute, or create derivative works from your work. This might not be what you intend.

Pro tip!

Yes, there’s really a legit “Do What the Fuck You Want to Public License”.

Tell npm who you are

npm set init.author.name “Channing Tatum”
npm set init.author.email “magic.mike@gmail.com
npm set init.author.url “http://www.magicmikemovie.com"

Your credentials will be now saved to a ~/.npmrc file and used as defaults whenever you initialize a npm package, so you don’t have to enter them each time.

To authenticate on your machine, log in with your npm username, password, and email.

npm login

Initialize a npm package

When you create a new module, you want to describe your package with the package.json file.

npm init

If you want to namespace your modules, do this instead

npm init --scope=username

Answer all the questions you’re prompted.

For the version, let’s start with

0.0.1

When you make changes to your library in the future, remember to update the version according to semantic versioning (SemVer).

I like to think of a version number that follows SemVer like this

Breaking down SemVer

SemVer isn’t used by all libraries. Some maintainers strongly believe that it makes no sense. They feel that any change to a library could potentially break backwards compatibility. In my experience, libraries that don’t follow SemVer cause more problems for the consumers, so I encourage you to follow it.

Answer the test command question with this

mocha --reporter spec

You should now see a package.json file in your project folder.

Specify a minimum Node version

By adding the following (optional) to your package.json, you can specify the minimum Node version that your package requires to ensure your library will work for your users.

"engines": {
"node": ">=4.2.4"
},

Create a node module

A Node/npm module is just a regular JavaScript file, but it must follow the CommonJS module spec. UMD, which is CommonJS compatible, also works.

Now, let’s create a very tiny module and name the file index.js.

'use strict';

/**
* Adds commas to a number
*
@param {number} number
*
@param {string} locale
*
@return {string}
*/
module.exports = function(number, locale) {
return number.toLocaleString(locale);
};

Confession: I know this module is pretty pointless since browser support is already there via the native toLocaleString method. However, I wanted to get this working in Node by passing in different locales, and I just couldn’t figure it out. Hints are welcome!

Side note: Sindre Sorhus is the author of over 600 modules on npm. He recently wrote a long GitHub comment about why we should use small modules.

Write some tests

I’m going to use the Mocha testing framework and Chai assertion library, but you can use whatever you like. In your project root

npm i mocha -D
npm i chai -D

Check your package.json file, and you should notice that both are now added to the “devDependencies” section since they are only required during development and not at runtime.

Fun facts!

  • -D is the same as --save-dev
  • -S is the same as --save

Create a test folder and a test.js file inside of it.

mkdir test && touch test/test.js

Add the following tests to the test.js file. I’m new to writing unit tests, so feel free to make them better.

'use strict';

var expect = require('chai').expect;
var numFormatter = require('../index');

describe('#numFormatter', function() {
it('should convert single digits', function() {
var result = numFormatter(1);
expect(result).to.equal('1');
});

it('should convert double digits', function() {
var result = numFormatter(12);
expect(result).to.equal('12');
});

it('should convert triple digits', function() {
var result = numFormatter(123);
expect(result).to.equal('123');
});

it('should convert 4 digits', function() {
var result = numFormatter(1234);
expect(result).to.equal('1,234');
});

it('should convert 5 digits', function() {
var result = numFormatter(12345);
expect(result).to.equal('12,345');
});

it('should convert 6 digits', function() {
var result = numFormatter(123456);
expect(result).to.equal('123,456');
});

it('should convert 7 digits', function() {
var result = numFormatter(1234567);
expect(result).to.equal('1,234,567');
});

it('should convert 8 digits', function() {
var result = numFormatter(12345678);
expect(result).to.equal('12,345,678');
});
});

Run our tests

Because our package.json file already has the following via npm init

"scripts": {
"test": "mocha --reporter spec"
}

You can now run your tests from your command line with

npm test

Change reporter type from “spec” to “nyan” for a little fun.

Write a good README

Update the README.md (markdown) file with details and usage examples for your users, especially since this will be displayed prominently on GitHub and npm.

Read this to learn the art of writing a good README, and here’s a good template.

Number Formatter
=========

A small library that adds commas to numbers

## Installation

`npm install @jdaudier/number-formatter`

## Usage

var numFormatter = require('@jdaudier/number-formatter');

var formattedNum = numFormatter(35666);


Output should be `35,666`


## Tests

`npm test`

## Contributing

In lieu of a formal style guide, take care to maintain the existing coding style. Add unit tests for any new or changed functionality. Lint and test your code.

Reminder: Don’t forget to update the README above with your own project name, and if you’re publishing a scoped module, update it to

@username/project-name

Note: It is also a common practice to have a separate CONTRIBUTING.md file for your contribution guidelines.

Commit & push to GitHub

Let’s create a version tag as well.

git add .
git commit -m “Initial release”
git tag v0.0.1 
git push origin master --tags

Publish to npm

npm publish

If you run into errors with the above command, it could mean that the package name is already taken. In that case, you might want to either rename or scope your package.

Scoped packages are private by default. To publish private modules, you need to be a paid private modules user.

However, public scoped modules are free and don’t require a paid subscription. To publish a public scoped module, set the access option when publishing it. This option will remain set for all subsequent publishes.

npm publish --access=public

Pro tip! When creating a scoped module, it’s a good idea to check your package.json before publishing just to make sure that the name of your package is “@username/project-name” — otherwise it won’t be scoped and if it’s meant to be private, it will end up being public by accident.

Log in to your npm account and your module should show up there. Congrats! You’ve just published your first Node module.

Add continuous integration

Travis CI is a lightweight continuous integration tool that runs tests on every commit to your GitHub repo, even pull requests. It’s free for open source projects.

Log in to your Travis CI account, and follow these steps

This is what your .travis.yml file should look like in the project root

language: node_js

node_js:
- stable

install:
- npm install

script:
- npm test

Commit and push to GitHub.

Log in to Travis to see your build status! You will also get email notifications.

Email notifications on build status from Travis

Add code coverage statistics

Istanbul is a JavaScript code coverage library that will check statement, branch, and function coverage statistics by inserting lines of code into your JavaScript as your tests run and then report back how many of its inserted lines were called.

Coveralls is a test coverage reporter that you can integrate with Travis. It formats the coverage data in a nice way. You can get pretty much everything from the reports from Istanbul, but only locally and less pretty.

npm i coveralls -D
npm i istanbul -D

Log in to Coveralls with your GitHub account, click the “ADD REPO” button, and toggle the switch to enable the repo for which you want code coverage statistics. To use Coveralls, your code must be hosted on GitHub or Bitbucket.

Configure your package.json file for Istanbul and Coveralls by adding a new script named “cover”:

"scripts": {
"test": "node_modules/.bin/mocha --reporter spec",
"cover": "node_modules/istanbul/lib/cli.js cover node_modules/mocha/bin/_mocha -- -R spec test/*"
},

And update your .travis.yml file to this

language: node_js
node_js:
- stable
install:
- npm install

script:
- npm run cover

# Send coverage data to Coveralls
after_script: "cat coverage/lcov.info | node_modules/coveralls/bin/coveralls.js"

Now you can run your tests and code coverage stats from your command line with

npm run cover

Now, commit and push to GitHub.

Travis will now invoke Istanbul, and Istanbul will run an lcovonly code coverage report, save that info to coverage/lcov.info, and pipe that data to the Coveralls library.

Log in to Coveralls to check and see if everything executed smoothly.

Add some sweet badges

Now that you’ve wired your repo to run tests on Travis and send coverage data to Coveralls, you’re probably wondering how to get those sweet badges on your GitHub and npm repos.

Travis

Click on the settings toggle next to your repo on Travis CI, and click on the badge icon.

Choose Markdown and add the code to your README.

Markdown code for Travis build status badge

Coveralls

Log in to Coveralls, click on your repo, click the “BADGE URLS” dropdown, and add the Markdown code to your README.

Markdown code for Coveralls code coverage badge

Commit and push to GitHub.

Travis will run your tests, and you can see your build status in your GitHub README.

Build passed

If the build succeeds, you should see this badge.

Build failed

If the build fails, you will see this.

Code coverage badge from Coveralls

You should also see another badge from Coveralls showing your code coverage stats.

Release a new version

Now that we have our sweet badges on GitHub, let’s get them on npm as well.

The only way to update npm is to release a new version, even if you’re just fixing a typo. npm will not allow you to re-publish to the same number.

So let’s create a new release by bumping the version in your package.json. To do that, you can use edit the file manually or use

npm version <update_type> -m "<message>"

where update_type is one of the semantic versioning release types:
patch, minor, or major.

So let’s do

npm version patch -m "Version %s - add sweet badges"

%s = the new version number.

This command will bump the version number in package.json, add a new commit, and tag it with this release number.

Note: Your Git working directory has to be clean before you can run npm version.

After bumping the version number

git push && git push --tags (or git push origin master --tags)
npm publish

Now if you go to your published module on npm, you should see your new release with the two sweet badges!

Test out your module

Create a new directory and a package.json file.

{
"dependencies": {
"project-name": "*"
}
}

Then from the command line

npm i

Create an index.js file with the following content

var numFormmater = require('project-name');

var formattedNum = numFormmater(234324234);

console.log(formattedNum);

Reminder: If you published a scoped module, update the project name to

@username/project-name

Then from the command line

node index

You should see a console log of

234,324,234
Oh, the sweet smell of success!

More info

Special thanks to