Speeding up your npm builds with Yarn

John Grubb
Director of Customer Care
15 Nov 2016

Say you have a decent sized project and your deployments are taking a while. Platform.sh rebuilds your entire application from scratch with each git push so in some cases the process of downloading all those 3rd party packages can take quite a while. We can and do manage local caches of some composer packages due to our PHP heritage, which helps to make  composer install  a pretty snappy affair, but it’s simply not possible to effectively do this with Nodejs.

Compounding this problem for npm is the fact that npm’s dependency graph, that is the dependencies of your dependencies, have to be worked out every time you run npm install. This can lead to developers in your org installing different versions of packages which will cause you problems.

Most other package managers overcome this with the use of a “lockfile”. A lockfile is a file that’s generated when you run  composer install  for the first time, or  bundle install  if you’re working Ruby. A lockfile is the result of the dependnecy graph being worked out, and then specifying the exact versions of each package. This file is checked into Git, and each dev in the project gets the exact same versions of the packages required for the project.

Enter Yarn

I was listening to the most recent Laravel podcast over the weekend and they got to talking about a new quasi-npm-replacement that had just come out called Yarn.

Yarn aims to be an almost drop in replacement for npm. There are a number of ways of installing it, but the most simple is just  npm install -g yarn . My coworkers thought I was trolling them with that, but it makes perfect sense if you think about it.

The only other step is run the  yarn  command locally in order to have Yarn traverse your node_modules directory and build up the Yarn lockfile -  yarn.lock . Then commit that to git and let’s rock and roll on your  .platform.app.yaml . We’re going to require Yarn in the global dependencies section -

dependencies:
  ruby:
    sass: "*" # not required, just assuming
  nodejs:
    gulp-cli: "*" # same here
    yarn: "*"

And then replace  npm install  in your  hook.build  with  yarn install  instead, like so -

hooks:
  build: |
    yarn install
    gulp default // for a Laravel project

This took my previously 6 minute builds down to about 1 minute. In other words, the time that it took out of my build phase was longer than the time it took to completely move from npm to Yarn in the first place. The reason for this speed boost is that Yarn doesn’t have to generate the dependency graph every single time (like npm does) since the lockfile, and Yarn downloads the packages in parallel rather than whatever npm does, which must be one at a time.

If you’re using  npm install  as part of your build step on Platform.sh, it’s really a no-brainer. Check it out!