Using npm like Bundler

Matteo Latini

1 Jul 2014 Development

Matteo Latini

3 mins
npm zoomed logo

Coming from a Ruby and Rails background, we've always found very strange how nowadays most JavaScript libraries that require Node Packaged Modules recommend some dependencies to be installed globally one by one. As Ruby developers that always felt strange to us. We'll see how to use npm like we use Bundler.

It seems that every recent JavaScript project has one or more npm install -g commands you should run to install some of the project's dependencies globally. That is bad for READMEs that grow bigger and bigger, bad for setup time because developers are forced to read much more instructions before being able to work and bad for your computer because you pollute system directories with development packages. So we've come up with this question: why on earth should you be installing stuff with npm install -g when npm is perfectly capable of running like Bundler does?

After years of hard work done by using the great tool that Bundler is, we don't like installing all those libraries globally. Conceptually we like projects and applications to be self-contained, standardized and easy to just pick up and play.

Basically this is the workflow every Rails developer knows and loves:

  1. install bundler with gem install bundler if not already installed;
  2. download an application, typically via git clone;
  3. cd inside the application and run bundle install.

These three steps are usually everything that's required to have the dependencies you need to start playing with the application (for example to start exploring with rails console). That also means that you can go from zero to the application running without even reading the README.

The same workflow seems unapplicable if you read the documentation of most npm packages. As a team we're still very much experimenting with JavaScript so we tend to change tools and libraries very often; we're still looking for the workflow that works best for us. That means we could be using different tools for different projects. Probably many developers are in our same exact position.

So this is why we've been trying to reproduce with npm the workflow we love with Bundler. We found that it is actually possible and quite easy.

Setup

As an example we'll demonstrate how to prepare an application from scratch by using ember-cli a utility we've been really interested in since it came out. It's basically a set of tools and templates to work with ember.

If you take a look at the project's Getting Started section you'll see there are plenty of tools you have to install by using npm install -g. We'll do it differently.

First of all make sure you have npm installed. In addition to installing npm you should add the local binaries folder to your $PATH environment variable. Since npm will use the local directory node_modules to keep all your packages (the binaries too), you need to have this:

PATH=./node_modules/.bin:$PATH

somewhere inside your ~/.zshrc or ~/.bashrc files.

Then create an empty folder which will host your project. From inside the project's directory you can run all the npm install commands without the -g flag and those will be installed in the ./node_modules path inside your project. You should also exclude this directory from your version control system as this directory will contain code you don't want in your repository.

To create an application with ember-cli:

$ npm install ember-cli
$ ember init
$ npm install --save-dev phantomjs bower

This will generate everything and keep track of the dependecies of your app inside the package.json file. Think of it as your Gemfile for JavaScript applications. The --save-dev flag will make sure npm changes package.json to reflect the dependecies you just installed.

To make sure developers don't fight with different versions of a dependency we can add a Gemfile.lock equivalent, like this:

$ npm shrinkwrap --dev

Npm will add a new npm-shrinkwrap.json that keeps track of the exact dependencies required to run your precious application (that you might want to keep in your repository). The --dev option makes sure development dependencies are tracked as well as production dependencies.

Using the npm-shrinkwrap.json file also has some benefits in production because it ensures you always have control of which versions will actually be installed in the production environment (just like Bundler).

Have fun

The procedure for setting up an application might be slightly longer than that required by Bundler but, after doing this, the next developer working on the application can just run:

$ npm install

after downloading the application to get all the dependencies required to use the application smoothly.

You may also like

Let’s redefine
eCommerce together.