Press enter or click to view image in full size
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 -gIf 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
- 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)
- Clone it locally
Press enter or click to view image in full size
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.
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 loginInitialize a npm package
When you create a new module, you want to describe your package with the package.json file.
npm initIf you want to namespace your modules, do this instead
npm init --scope=usernameAnswer all the questions you’re prompted.
For the version, let’s start with
0.1.0When 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
Press enter or click to view image in full size
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 specYou 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 -DCheck 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.jsAdd 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 testChange 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-nameNote: 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.1.0git push origin master --tags
Publish to npm
npm publishIf 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=publicPro 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.
Get Joanne’s stories in your inbox
Join Medium for free to get updates from this writer.
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
Press enter or click to view image in full size
This is what your .travis.yml file should look like in the project root
language: node_jsnode_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.
Press enter or click to view image in full size
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 -DLog 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_jsnode_js:
- stableinstall:
- npm installscript:
- 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 coverNow, 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.
Press enter or click to view image in full size
Coveralls
Log in to Coveralls, click on your repo, click the “BADGE URLS” dropdown, and add the Markdown code to your README.
Press enter or click to view image in full size
Commit and push to GitHub.
Travis will run your tests, and you can see your build status in your GitHub README.
Press enter or click to view image in full size
If the build succeeds, you should see this badge.
If the build fails, you will see this.
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 iCreate 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-nameThen from the command line
node indexYou should see a console log of
234,324,234More info
- Sample repo with completed code
- Checklist for Your New Open Source JavaScript Project
- Authoring Node Modules
- npm past, present and future
- Building Better npm Modules with Travis and Coveralls
- Be a Good npm Module!
- How to be a Better Node Module Maintainer
- Code Coverage Statistics Using Coveralls and Istanbul
- Developer’s Guide to Open Source Licenses
- Badges, Badges, Badges
- Symlink a Package Folder — SUPER useful for working on modules before publishing them, especially in the context of a larger app
Special thanks to
- Quick Left’s post on the same topic
- Paul Falgout, James Smith, Justin Ridgewell for reviewing this (best brain trust ever)
- Raquel Vélez for giving me great suggestions from an insider’s POV