As part of our recent work on backbone.hypermedia at Linn I’ve spent some time familiarising myself with Grunt. With very little effort - we built a workflow which enables us to publish to npm, NuGet and Bower with a single command. In this post I describe how we arrived at this solution in the hope that it may prove useful to others.
The library we are publishing is backbone.hypermedia - a Backbone plugin which provides facilities for interacting with a hypermedia API.
The library is fairly small, and has a handful of dependencies:
Publishing to NuGet
NuGet is a package manager for .NET. At Linn we develop our HTTP services using C# - so publishing to NuGet makes sense because we already manage other dependencies through NuGet.
grunt-nuget is a Grunt plugin which provides tasks for creating and publishing a package to NuGet. Firstly we install the plugin as a development dependency:
Then we load the tasks in Gruntfile.js:
And configure them as follows:
grunt.file.readJSON loads the contents of package.json into a variable
pkg which we subsequently refer to within a Grunt template to pass the version to the
nugetpack task generates a .nupkg file from a .nuspec manifest. You can see the contents of our .nuspec file on GitHub.
Once the package file has been created,
nugetpush takes care of publishing the package to the NuGet repository. Prior to executing this task for the first time you must declare your NuGet API key by executing:
You only need to do this once.
We then defined an alias in Gruntfile.js to perform both tasks in sequence:
All credit for implementing the NuGet publishing goes to Henry Wilson.
Publishing to npm
npm is a package manager for Node.js. I initially introduced npm as a means of implementing CI through Travis CI. However once I became familiar with Grunt, the ease at which we could automate other tasks became clear.
With an appropriately populated package.json, publishing to npm is as simple as executing:
So at this point, our workflow for releasing a new version was:
But we were keen to wrap the two steps together to make it super simple, and we also wanted to automate the cleanup of old .nupkg files.
My initial plan was to use grunt-shell to execute the commands one at a time. Then I discovered grunt-release which automates various steps, including publishing to npm, and automatically incrementing the version number in package.json. This was appealing as I had already forgotten to increment the version at least once when attempting to publish a new release.
As before, we install the plugin:
Load the tasks:
And configure them:
You might be asking yourself why I’m setting
false here. Well, it turns out that unfortunately grunt-release does not provide a facility (that I’m aware of) to reload the
pkg variable after the version has been bumped. Since we rely on passing this version to our
nugetpack task, this presents a problem - as the version would be incorrect. I’ve opened an issue to suggest adding this feature.
I then found grunt-bump, which is a similar plugin which does support reloading config variables, but does not support publishing to npm (also suggested). The solution I came up with was to use grunt-bump to increment the version, and grunt-release to publish to npm. This way the
pkg variable is updated and the
nugetpack task works as intended.
First install grunt-bump:
Then load the task into Gruntfile.js:
And configure it to bump the version and reload the
We use grunt-contrib-clean to clean up the old .nupkg files.
grunt-bump supports three different task targets to facilitate bumping the major, minor or patch release numbers. To make use of this, we enhanced our
publish task alias as follows:
So now we can do:
To publish a patch release to NuGet and npm. This is short-hand for
As before, but bumps minor version.
As before, but bumps major version.
In addition to publishing the packages, grunt-release also commits the updated package.json and does a git push.
Publishing to Bower
Bower is yet another package manager, specifically aimed at managing packages for front-end development. You can manage dependencies for front-end development using npm, but npm’s nested dependency tree isn’t always appropriate for this. In constrast, Bower requires a flat dependency tree.
Bower is somewhat different to NuGet and npm in that there is no package repository as such. Instead, a Bower package is simply an alias which points to a git endpoint.
You can install Bower globally using:
You must then add a bower.json manifest to the root of your repo. You can create one interactively using
bower init. Bower will pick up versions from semver git tags on your repo. Conveniently grunt-release already takes care of creating such tags as well as pushing them. So with the git tags in place, publishing to Bower is simply a case of executing a one off command to register the package alias:
And that’s it. So now our workflow for releasing to three different package managers simultaneously is as simple as typing