Working around broken nested NPM dependencies in old project

Recently I had to re-deploy an old Node.js project, which still runs node.js v0.10.x (it is pointless to upgrade it, a whole new project will replace it soon).

What I found is that quite a few nested dependencies ended up not working with Node.js v0.10 (it was a long chain of dependencies, each linking to a "too new" version of their dependencies due to not an optimal semver)

One solution one can find online is to use npm shrinkwrap --dev to generate an npm-shrinkwrap.json file, and manually update its content to point to the right versions of the nested dependencies. The problem is - there were too many of these to update since many nested dependencies I had to change in turn had their dependencies, and tracking all that down manually was just not feasible.

For example - one of the modules was depending on module request with semver ^2.34.0. Which in turn picked up the latest available version 2.84.0. The problem is - 2.34.0 works with node v0.10, while 2.84.0 does not, since the latter relies on the support of some ES6 features, like const. That is a bug in versioning, but there is no quick way for me to fix it, so I had to work around it.

The workaround, once found, was relatively easy. I started with a clean slate and removed node_modules:

rm -rf node_modules

After that I installed all the modules, and, since in my case npm i would break due to scripts running as part of the post-install process, I needed to disable the post install scripts:

npm install --ignore-scripts

Now, for each problematic dependency I would cd into its folder and manually install a working version of the dependency. To find the right version I simply open package.json and check version in there. Like with the module request above, I saw that originally the author relied on the version of request@2.34.0 and that is what I will manually install:

cd node_modules/dependency_causing_troubles
npm i --save --save-exact request@2.34.0
cd -

That will force module dependency_causing_troubles to use the version of request set at exactly to 2.34.0.

Obviously, the whole thing will break down right after next npm install during deployment to a new host. To make sure we get the same repeatable build, we will use NPM's shrinkwrap feature:

npm shrinkwrap --dev

That will create npm-shrinkwrap.json which NPM will use instead of package.json when installing dependencies. And that file lists exact versions and exact URLs to download these modules from, so you will get exact 1:1 build on the host you are deploying it on.

Commit that npm-shrinkwrap.json into your repo and deploy.