You’ve already built your Node package and published it to the Node Package Manager site. Perhaps you even followed my last post on the what, why and how of building Node packages to do this. But you’re ready to start making improvements and you don’t know quite how to start. This is a guide on some basic things you might be missing and how to include them.

Add a readme file

There are things I didn’t cover last post that make crucial additions to your Node package. One of the most obvious is a README.md file, which I’ll call “readme file” from hereon out.

At worst, readme files can be mere “hygiene factors” for your package. But at best they can actually serve as a motivator for using the tool and they can provide the central focus to the other improvements you might like to make.

Hygiene factors

For those who don’t know what a hygiene factor is, you can read the Wikipedia page on Frederick Herzberg’s two-factor theory. Or you can imagine the work involved in cleaning your kitchen just so you can use it.

When you clean a kitchen, you’re not adding anything to the kitchen as such. But without undertaking this chore you can’t use the kitchen, not safely anyway. Hygiene factors are like this; they’re the bits of work that need to be there even if their use goes unnoticed. As a recovering bass guitarist, I like to think of the bass in much rock and pop music as being a hygiene factor – most people only notice when it’s not there.

My bass guitars often went unheard.

In the case of readme files they provide some reassurance about the package. You’d notice it if it weren’t there. But that doesn’t mean they can’t add value.

Key sections

For me, there are a few sections I look for automatically when I look at a readme file.

  • Version. Just knowing that the package/code is versioned is helpful!
  • Installation. Clear, simple, short instructions on how to install even if seems as obvious as npm install put me at ease.
  • Usage. A short 5-10 line code example of how the package is used is also reassuring and gives me a template with which to start.
  • Documentation/information. A link to further documentation or information on how to use the package/code and the various features will help me find out how to do what I’m looking to do.

Versioning your package

A key component of maintaining a Node package once you’ve built it that I didn’t cover last post was versioning.

The Node Packager Manager (NPM) tool on the command line actually makes these really easy. You just need to understand semantic versioning first.

Semantic versioning

Here I’ve attempted to provide a summary of how semantic versioning works although you may want to read the official page on semantic versioning to get more detail.

In semantic versioning, the version for a package consists of a series of three numbers separated by dots:

  1. The first number is the major version number. This should only need to change when some feature is broken or has been replaced affecting compatibility.
  2. The second number is the minor version number. This should only change when new features are introduced or when features are deprecated so that the changes are backwards-compatible.
  3. The third number is the patch version. This should be used only for fixes; nothing fundamental about the features should change.

It’s possible to include further numbers and details after these three but that’s not essential.

When a version number for a package is changed, it’s quite common to say the version is “bumped”.

NPM version command

NPM has a command for handling versioning baked into it. You can simply write npm version followed by type of bump you want to make to the package and it will update the version number for you.

So for the types of “bump” mentioned above:

  • npm version major will change the version number from, for example, 1.0.0 to 2.0.0. This tells the user that if they have written code for version 1.*.* of your package, it may not work if they upgrade to 2.0.0.
  • npm version minor will change the version number from, for example, 1.0.0 to 1.1.0. It lets users of the package know that their code should still work but there are additional features or deprecated features that they can rewrite their code around.
  • npm version patch will change the version number from, for example 1.0.0 to 1.0.1. It suggests that something has been fixed in the package so this is an improvement to the code that should require no adjustments by the user.

All these commands will both tag your Git repository with the latest version number and update the version number in package.json to ensure consistency for the release.

Readme and versioning

You may want to tie the version number bump into your readme file. After all stating the version number up front in your readme file is useful. But you won’t want to have to remember to manually update the readme file everytime you use npm version. So you’ll have to use additional script to handle this.

A reminder about scripts

If you read my preceding post on building a Node package, you may recall that there was a section on the scripts part of package.json. This is a place where you can specify shortcuts to run commands for you. For example you can specify the command test in this way:

"scripts": {
    "test": "mocha"
}

With this code in your package file, you can use the command npm run test (or actually, in this particular case, just npm test for short) and it will run Mocha automatically for you. This way whatever testing suite you use, a user of your package only has to type npm test to get the report.

Automated versioning

It’s also possible to piggyback off existing NPM commands, like npm version. By specifying a script for “version”, you can have NPM run additional commands on top of the usual versioning work that it normally carries out.

For example, imagine adding a version script to package.json that prints the message “Bumping version…”

"scripts": {
    "test": "mocha",
    "version": "echo Bumping version..."
}

As you might recognise from the example in the code, it’s simple command-line syntax that the script properties expect. Running npm version will not only bump the version number as usual but with this version script in package.json it will also print the message “Bumping version” to tell you it will.

Versioning variable

We can actually use a variable to make this version bump message more informative:

"scripts": {
    "test": "mocha",
    "version": "echo Bumping version to $npm_package_version"
}

Using that dollar-prefixed variable will now print the new version number on the end of the message.

Rewriting the readme

We can use this approach and the variable to automate the updating of the readme file.

For example, I originally added the version v0.0.0 to the readme file in my dickie-dates package. To change that version number automatically when I used npm version, I wrote the following script in a file called version.js.

var fs = require("fs")

fs.readFile("README.md", "utf8", function (error, data) {
	if (error) throw error
	var bumped = data.replace(/(\d+\.\d+\.\d+)/g, process.argv[2] || "$1")
	fs.writeFile("README.md", bumped, function (error) {
		if (error) throw error
		console.log(process.argv[2] ? `Bumped readme file to ${process.argv[2]}` : `Version number not found.
	})
})

This script reads the readme file and replaces anything that looks like a version number the new version number.

Packaging the script

The script relies on an argument being passed to it – hence the use of process.argv[2] in the code above. The variable process.argv[2] will either be the new version number or it will be undefined, in which case the code will simply use what was there before ($1).

To make this work, the script file version.js needs calling from the "version" property within the scripts section of package.json.

"scripts": {
  "test": "mocha",
  "version": "node ./version.js $npm_package_version && git add README.md"
}

Note that the version.js script is called using the node command, that the environment variable for the package version number is passed to it, and that the changed README.md file is staged with git add. The normal operation of npm version takes care of the git commit after the file has been staged.

You can read more about this on the NPM page on adding scripts to the version command.

Version badging

In the code given above, my version.js file will look for anything that looks like a version number. This could be quite dangerous as it may pick up numbers that look like versioning numbers in future instances of the readme file.

Targeted updates

The problem code is the regular expression /(\d+\.\d+\.\d+)/g which looks to replace any three sets of one or more digits separated by dots.

One way to help prevent this would be to make the string that needs to be replaced more specific.

You may have noticed that many readme files use neat little graphics to show build status and other information about the site.

For example, the readme for the Express package has badges for the version, downloads, and test pass rate and coverage.

We could use this approach to present the version information more neatly and to make our replacement script more targetted.

Using shields.io

The badges can be created automatically using the website shields.io.

By creating an address based on just three components – subject, status, and color – you can get an image for your readme file immediately. The address takes this format:

https://img.shields.io/badge/<SUBJECT>-<STATUS>-<COLOR>.svg

You can try this out for yourself using the Shields.io “Your Badge” form.

Take the version number we asked our build script to handle. Rather than adding this as raw text to the readme file we could instead ask Shields.io for an image that contains this information:

https://img.shields.io/badge/version-0.0.0-gray.svg

That address will give us the following image.

Version 0.0.0 of any package presented as a grey shield.

You don’t want to have to manually test and then update these yourself each time – this is the perfect candidate for something that can be added to your package.json scripts.

Rewriting version.js

First we can replace v0.0.0 (or whatever the version is) in the original readme file with the appropriate Markdown code for displaying an image from sheilds.io:

![Version 0.0.0](https://img.shields.io/badge/version-0.0.0-gray.svg)

The file version.js then needs updating to find this specific line within the readme file and replace the version numbers within this line of Markdown code with the new version number. This is much safer than targetting a set of numbers as the numbers are likely to appear for reasons besides versioning, meaning the script risks replacing these too.

To make the script more targetted, the regular expression needs changing first:

/(!\[Version )(\d+\.\d+\.\d+)(\]\(https:\/\/img\.shields\.io\/badge\/version-)(\d+\.\d+\.\d+)(-gray\.svg\))/g

This regular expression looks for our Markdown image line but with any version number. As you can see in the visualisation of the regular expression below, it also groups the line it finds into parts so that we can target just the numbers for change and keep the rest.

Regex visualisation shows what `version.js` is looking for.

Groups 2 and 4 as captured by this regular expression are the ones to be replaced. So the replace function in version.js can be adapted to reflect this.

var bumped = data.replace(/(!\[Version )(\d+\.\d+\.\d+)(\]\(https:\/\/img\.shields\.io\/badge\/version-)(\d+\.\d+\.\d+)(-gray\.svg\))/g,  `$1${process.argv[2] || "$2"}$3${process.argv[2] || "$4"}$5`)

This will now make the automated updating of README.md more robust and more aesthetically pleasing.

Summary

In this post, I’ve covered:

  • The importance of adding even a simple readme file, as a hygiene factor.
  • Semantic versioning and using it for your Node package.
  • Combining the two by writing an automatically updated version badge on your readme.

For what it’s worth, you also learned that I used to play bass guitar.

There are other ways to do the things described in this post, packaging and build tools that will allow you automate it similar ways. But I wanted to write about the principles and basics behind these hygiene factors without getting bogged down in explaining other packages, and the best way to do that seemed to be to use as vanilla techniques as I could think of.

You can see all three things implemented at the Node package I described creating in my post on creating your first Node package. That package is called dickie-dates and can be found at:

Next

In this post, I’ve explored the reasons for creating a readme for you package and a way to version your package – and then I’ve pulled the two things together.

Originally, I wanted to write more about badges and something about continuous integration too, binding the results of automated testing into your readme file. But that looks to be a separate post.

In the meantime, I also have some specific improvements I want to talk about making to my dickie-dates package.