terug naar overzicht

Daan Stolp

+31 35 539 09 09


19/02/19

Version management of npm packages

If you have been working on JavaScript projects for a while and have used npm, you have probably run into issues with package versions. Maybe your automated build fails, while everything works just fine on your laptop. Or you cannot get an existing project to run on your new machine, while your team mates have no problems at all with the exact same code base. Version differences between npm packages can cause quite some headaches, so how can you keep some sanity in all of this?

If you have been working on JavaScript projects for a while and have used npm, you have probably run into issues with package versions. Maybe your automated build fails, while everything works just fine on your laptop. Or you cannot get an existing project to run on your new machine, while your team mates have no problems at all u003cemu003ewith the exact same code baseu003c/emu003e. Version differences between npm packages can cause quite some headaches, so how can you keep some sanity in all of this? Let’s examine how it all works.

Minor differences between versions could break the build

As you can see, this can be quite a ‘relaxed’ way of specifying versions. This has the potential benefit of receiving minor upgrades and security patches of your dependencies, without requiring any configuration change on your part. That’s a good thing, and during active development, that’s probably what you want. Besides, theoretically, minor and patch updates u003cemu003eshouldu003c/emu003e never contain any breaking changes…rnrnHowever, we don’t live in a perfect world, and sometimes even the smallest update of a package can introduce problems. So if your build server installs a slightly different version than your development laptop, things may suddenly and unexpectedly break. So how do we deal with this?rnrnWe u003cemu003ecouldu003c/emu003e resort to only specifying exact versions in our u003ccodeu003epackage.jsonu003c/codeu003e file. But this has two drawbacks. First, we lose the benefit of easy updates to minor or patch versions. And secondly, we still cannot control our dependencies’ dependencies.rnrnLet’s say we depend on version 1.1.0 of Package A, and Package A in turn depends on version u003ccodeu003e^2.1.1u003c/codeu003e of Package B. Notice the u003ccodeu003e^u003c/codeu003e in front: package A only depends on the major version, any version 2.* will be allowed. In this scenario, we cannot guarantee which version of Package B we get. We might get version 2.1.1, but it could also be 2.1.8 or 2.3.0, since Package A only specified a dependency on the major version number. So while we have locked down our direct dependency, we still don’t control the entire package tree.rnrnFortunately, there are some mechanism to lock down the exact versions. Let’s see how that works.

The package-lock.json file “logs” which versions were installed

When you run u003ccodeu003enpm installu003c/codeu003e, npm creates a u003ccodeu003epackage-lock.jsonu003c/codeu003e file. The name is somewhat confusing, as it might suggest that this file somehow “locks down” which version of packages gets installed. Instead, it is best thought of as a “log”: a file that lists which exact versions of packages were installed at the time. When you run u003ccodeu003enpm installu003c/codeu003e again after a few days or weeks, when new versions of some packages are available, npm will update the existing u003ccodeu003epackage-lock.jsonu003c/codeu003e file to create an updated log of the installed package versions.rnrnNote that the u003ccodeu003epackage-lock.jsonu003c/codeu003e lists u003cemu003eallu003c/emu003e packages that are installed. So not just the primary packages on which your project depends, but also of those packages’ dependencies. In this way, the u003ccodeu003epackage-lock.jsonu003c/codeu003e file is an exact manifest of all packages that were installed at a certain time. This is very helpful! It means that when we have a working installation on our development laptop and we commit the corresponding u003ccodeu003epackage-lock.jsonu003c/codeu003e file, we at least have a ‘recipe’ that can guarantee a working configuration.rnrnNow we just need one more missing piece: how can we restore a working installation from this committed u003ccodeu003epackage-lock.jsonu003c/codeu003e file?

Delen