"DRINK ME" [Why I do not include npm-shrinkwrap.json in Node.js tool packages]
I maintain a few open source projects and get asked some of the same questions from time to time. I wrote the explanation below in August of 2023 and posted it as a GitHub Gist; I am capturing it here for easier reference.
Background:
For historical purposes and possible future reference, here are my notes on why I backed out a change to use npm-shrinkwrap.json
in markdownlint-cli2
.
The basic problem is that npm will include platform-specific packages in npm-shrinkwrap.json
. Specifically, if one generates npm-shrinkwrap.json
on Mac, it may include components (like fsevents
) that are only supported on Mac. Attempts to use a published package with such a npm-shrinkwrap.json
on a different platform like Linux or Windows fails with EBADPLATFORM
. This seems (to me, currently) like a fundamental and fatal flaw with the way npm implements npm-shrinkwrap.json
. And while there are ways npm might address this problem, the current state of things seems unusably broken.
To make this concrete, the result of running rm npm-shrinkwrap.json && npm install && npm shrinkwrap
for this project on macOS can be found here: https://github.com/DavidAnson/markdownlint-cli2/blob/v0.9.0/npm-shrinkwrap.json. Note that fsevents
is an optional Mac-only dependency: https://github.com/DavidAnson/markdownlint-cli2/blob/66b36d1681566451da8d56dcef4bb7a193cdf302/npm-shrinkwrap.json#L1955-L1958. Including it is not wrong per se, but sets the stage for failure as reproduced via GitHub Codespaces:
@DavidAnson > /workspaces/temp (main) $ ls
@DavidAnson > /workspaces/temp (main) $ node --version
v20.5.1
@DavidAnson > /workspaces/temp (main) $ npm --version
9.8.0
@DavidAnson > /workspaces/temp (main) $ npm install markdownlint-cli2@v0.9.0
npm WARN deprecated date-format@0.0.2: 0.x is no longer supported. Please upgrade to 4.x or higher.
added 442 packages in 4s
9 packages are looking for funding
run `npm fund` for details
@DavidAnson > /workspaces/temp (main) $ npm clean-install
npm ERR! code EBADPLATFORM
npm ERR! notsup Unsupported platform for fsevents@2.3.3: wanted {"os":"darwin"} (current: {"os":"linux"})
npm ERR! notsup Valid os: darwin
npm ERR! notsup Actual os: linux
npm ERR! A complete log of this run can be found in: /home/codespace/.npm/_logs/2023-08-27T18_24_58_585Z-debug-0.log
@DavidAnson > /workspaces/temp (main) $
Note that the initial package install succeeded, but the subsequent attempt to use clean-install
failed due to the platform mismatch. This is a basic scenario and the user is completely blocked at this point.
Because this is a second-level failure, it is not caught by most reasonable continuous integration configurations which work from the current project directory instead of installing and testing via the packed .tgz
file. However, attempts to reproduce this failure in CI via .tgz
were unsuccessful: https://github.com/DavidAnson/markdownlint-cli2/commit/f9bcd599b3e6dbc8d2ebc631b13e922c5d0df8c0. From what I can tell, npm install of a local .tgz
file is handled differently than when that same (identical) file is installed via the package repository.
While there are some efforts to test the .tgz
scenario better (for example: https://github.com/boneskull/midnight-smoker), better testing does not solve the fundamental problem that npm-shrinkwrap.json
is a platform-specific file that gets used by npm in a cross-platform manner.
Unrelated, but notable: npm installs ALL package dependencies when npm-shrinkwrap.json
is present - even in a context where it would normally NOT install devDependencies
. Contrast the 442 packages installed above vs. the 40 when --omit=dev
is used explicitly:
@DavidAnson > /workspaces/temp (main) $ npm install markdownlint-cli2@v0.9.0 --omit=dev
added 40 packages in 1s
9 packages are looking for funding
run `npm fund` for details
@DavidAnson > /workspaces/temp (main) $
But the default behavior of a dependency install in this manner is not to include devDependencies
as seen when installing a version of this package without npm-shrinkwrap.json
:
@DavidAnson > /workspaces/temp (main) $ npm install markdownlint-cli2@v0.9.2
added 35 packages in 2s
7 packages are looking for funding
run `npm fund` for details
@DavidAnson > /workspaces/temp (main) $
References:
- Request and discussion: Commit package-lock.json #186
- Problem and investigation: v0.9.0: shinkwrap causes all dev dependencies to be installed #198