Sane Versioning in nodejs

December 9, 2017

node.js packaging

node.js and npm have been through a lot since I started using them. From whether or not to commit dependencies (THE HORROR) to git, to slow installations, you name it.

One of the most horrific atrocities for me has always been the fact that the version is hardcoded in the file package.json.


It has always peskered me that it’s not simply taken from a git tag, like sane languages do.

However, since it’s the common practice, and besides annoying me, it didn’t block anything important enough, I never really did something about it until recently.

ALAS, The need emerged

At BigPanda, all our node.js services are created as an artifact as a part of the CI process, to speed up deployment time.

In addition, the node.js libraries are precompiled and “dumbed down” using babel so they can be consumed by any node.js runtime that might need them, then packaged as an artifact (npm package) to be downloaded as a dependency.

This has worked good for a while, but it creates one limitation, to release a feature (merge a feature branch), you need to create an additional commit just for bumping the version in package.json.

Whilst this might not look like an issue, it prevents something extremely useful, and that’s blocking merges until reviewed in Github pull requests.

This finally annoyed us enough to solve the issue (no more cowboy merges), and here’s how we solved it.

The solution

In each node.js library or service, the package.json contains the version 0.0.0, which is the “dev” version.

'Take package.json to /dev/null'

At the CI build, before creating the artifact to be uploaded (service or npm package), we bump the package.json’s version with latest git tag, using the following command:

npm version --no-git-tag-version $(git describe | cut  -c 2- | awk -F \- '{print $1};')

'Bash to the rescue!'

This might seem a bit magic, but it simply uses the latest git tag, which in our cases looks like this vX.Y.Z, where X is the major, Y is the minor and Z is the pebble (Semver style).

The --no-git-tag-version parameter makes npm only change package.json, without adding a tag or a commit for the bump.

This means that each service and library’s artifact includes the correct version in the archived package.json.

Unt Voila! No extra commit to bump the version, and we can make sure by using Github’s protected branches feature, that no merges are done without review (and tests).

The only small issue left is at dev time, where our devs need to do git describe to see what version they’re on, but that’s a no brainer, and solved through a process.

But that’s not the standard?!?!

Well yes, you are right, that’s not how it’s done in node.js, it’s better.

'Thug Panda'

comments powered by Disqus