node.jsnpmnpm-install

Can NPM ignore platform-specific packages in lockfiles (eg, linux, darwin, etc)


Node packages that use fast native binaries often distribute them in architecture-dependent packages as dependencies that then get their own entries in package-lock.json. When this lockfile is checked in and then fetched by someone else on a different platform, npm ci will happily install the "incorrect" platform packages but cli commands will then fail with missing package errors. Even if you don't have a mixed-platform team, you still may run into problems if you use Docker or GitHub actions.

Is there a general way in npm or any other package manager to ignore particular dependencies from locking and have them resolve each time an install is performed?

For example, when installing Vite 5 on Linux, it will add lock entries for rollup and ultimately @esbuild/linux-x64, which will not work on a Mac. esbuild has a wasm package that can be used instead, but this is a problem for other packages as well (eg. @tauri-app/cli).

What I would like is to be able to pull a project and be able to run npm ci or npm i and have it actually install dependency binaries for my platform and not just what's in the lockfile.

Not great solutions I've considered:

  1. There is an easy workaround by just deleting the lockfile and node_modules directory and running npm i again, but this marks the lockfile modified. You could also remove and ignore the lockfile from the repository. However, both of these have the potential to cause other problems.
  2. Overrides is another way to do it, but the package has to supply a platform independent package and they don't all do this, and they aren't always fully compatible.
  3. You could potentially use a postinstall script to manually install all the packages needed by the current arch, but that seems messy and prone to breaking if nested dependencies change.

Solution

  • After some hours of trying various manual install methods I actually found a solution. In package.json you can set "cpu" and "os" options that the documentation states is for specifying platforms your module will run on. It's not clear, but one effect of this is that a lock entry will be created for each combination of os/cpu for each relevant package, and when npm ci is run, only the relevant packages will be installed on the target system.

    The solution is not to "ignore" lock entries, but to explicitly add any platform that you might want to run build tools on.

    For example: