In my current project at IsApp we’ve been considering a migration due to
a lot of frustrating some problems dealing with
npm-shrinkwrap to lock package versions.
Well, let’s talk about that for start…
WTF is npm-shrinkwrap?
npm-shrinkwrap is a feature of NPM to lock down package versions. It’s a command that generates a file named
npm-shrinkwrap.json (wth it’s not just
npm.lock) with quite the same concept behind
Gemfile.lock (for Ruby Bundler) or
composer.lock (for PHP Composer). It writes down the current version of every installed package in the working tree.
Once generated, any attempt to
npm install will respect this file in two ways:
- For a project installation, it installs the exact same versions of the packages listed on
npm-shrinkwrap.json. So we can guarantee that the same environment runs on development, test and production.
- For new package installations, it updates
npm-shrinkwrap.jsonwith the new installed versions.
The problem is that it’s not so reliable as it should. It changes thousands of lines to
npm-shrinkwrap.json after any simple install and insists in adding development dependencies to it without being requested, so we had to manually update the file from time to time. In short, it sux.
Yarn to the rescue
I’ve been using Yarn for some weeks only, but despite my initial reluctance in using anything beyond the node default tools, I’m quite satisfied.
Yarn always uses a
yarn.lock (now this name makes sense) file. Which means that either you don’t have to worry about generating/updating it nor you can ignore it.
yarn.lock is a simple text file instead of a json one and, in my tests, it remains very consistent between new package installs. But it has even more benefits.
Cache and faster install
Npm seems to completely ignore local cache, as it always take a lot of time to install packages, even if you have already installed them before in other projects. Yarn, on the other hand, can be very fast once it has a cache.
I’ve collected some benchmarks comparing Npm and Yarn using the GNU
time command and the express.js repository as example.
The results are bellow (full comparisons on gist):
|npm install||yarn install|
|clean install (no cache)||19.70s||6.93s|
|cached and lockfile present||13.90s||2.10s|
|cached and node_modules present||1.49s||4.18s|
|cached, lockfile and node_modules present||1.63s||0.67s|
Just to summarize…
In a clean install Yarn can be 3 times faster than Npm. Reducing to almost 5 times faster when the packages are cached. With the lockfile present it took less than one second on the example project.
It’s f****** fast!
Yarn for the win
I would not suggest migrating to Yarn on small or new projects. In other words, if Npm can handle your project well, just keep with it.
But if you work on a huge project with lots of dependencies that takes a lot of time to install or if having a lockfile is mandatory, Yarn can help a lot, so consider using it.
Nevertheless, Yarn still uses
package.json and so it’s fully compatible with Npm (despite the lockfile). So you can still install and run any Yarn project using Npm.