乐闻世界logo
搜索文章和话题

Why does "npm install" rewrite package- lock.json ?

5 个月前提问
3 个月前修改
浏览次数171

6个答案

1
2
3
4
5
6

在默认情况下,运行 npm install 不会重新生成整个 package-lock.json 文件。npm install 主要有两个目的:

  1. 在没有 package-lock.json 文件时,安装 package.json 中定义的依赖并生成一个新的 package-lock.json 文件。这个新生成的文件确保了未来的安装能得到相同版本的依赖,使得项目更加稳定可靠。
  2. 当已经存在 package-lock.json 文件时,npm install 会依照这个文件安装确切版本的依赖,以保证所有使用该项目的开发者都有着一致的依赖树。

然而,当你添加新的包或者更新现有包的版本时,例如使用 npm install <package>npm install <package>@<version>npm 会更新 package.json 并相应地调整 package-lock.json 来反映新的依赖信息。这种情况下,package-lock.json 文件确实会被修改,但不是完全重写,而是更新或添加了相关依赖的条目。

例如,假设我正在开发一个使用 Express.js 的 Node.js 应用,并且我希望安装一个新的依赖,比如 axios。我会运行:

sh
npm install axios

此命令会将 axios 添加到 package.json 文件中,并更新 package-lock.json 文件以包含 axios 及其所有子依赖的确切版本信息。如果我已经安装了 axios,但是我想要升级到一个新版本,我可以指定版本号:

sh
npm install axios@0.21.1

这将会更新 package.jsonpackage-lock.json 文件,以反映我所选择的 axios 版本。这样的更新是选择性的,并且仅针对被修改或添加的依赖部分。

如果确实需要重新生成 package-lock.json 文件,可以删除已有的 package-lock.json 文件和 node_modules 目录,然后运行 npm install,这样会基于 package.json 中的依赖重新创建一个新的 package-lock.json 文件及安装所有依赖。但在日常开发中,这通常是不必要的。

2024年6月29日 12:07 回复

Update 3: As other answers point out as well, the npm ci command got introduced in npm 5.7.0 as additional way to achieve fast and reproducible builds in the CI context. See the documentation and npm blog for further information.


Update 2: The issue to update and clarify the documentation is GitHub issue #18103.


Update 1: The behaviour that was described below got fixed in npm 5.4.2: the currently intended behaviour is outlined in GitHub issue #17979.


Original answer (pre-5.4.2): The behaviour of package-lock.json was changed in npm 5.1.0 as discussed in issue #16866. The behaviour that you observe is apparently intended by npm as of version 5.1.0.

That means that package.json can override package-lock.json whenever a newer version is found for a dependency in package.json. If you want to pin your dependencies effectively, you now must specify the versions without a prefix, e.g., you need to write them as 1.2.0 instead of ~1.2.0 or ^1.2.0. Then the combination of package.json and package-lock.json will yield reproducible builds. To be clear: package-lock.json alone no longer locks the root level dependencies!

Whether this design decision was good or not is arguable, there is an ongoing discussion resulting from this confusion on GitHub in issue #17979. (In my eyes it is a questionable decision; at least the name lock doesn't hold true any longer.)

One more side note: there is also a restriction for registries that don’t support immutable packages, such as when you pull packages directly from GitHub instead of npmjs.org. See this documentation of package locks for further explanation.

2024年6月29日 12:07 回复

I've found that there will be a new version of npm 5.7.1 with the new command npm ci, that will install from package-lock.json only

The new npm ci command installs from your lock-file ONLY. If your package.json and your lock-file are out of sync then it will report an error.

It works by throwing away your node_modules and recreating it from scratch.

Beyond guaranteeing you that you'll only get what is in your lock-file it's also much faster (2x-10x!) than npm install when you don't start with a node_modules.

As you may take from the name, we expect it to be a big boon to continuous integration environments. We also expect that folks who do production deploys from git tags will see major gains.

2024年6月29日 12:07 回复

Short Answer:

  • npm install honors package-lock.json only if it satisfies the requirements of package.json.
  • If it doesn't satisfy those requirements, packages are updated & package-lock is overwritten.
  • If you want the install to fail instead of overwriting package-lock when this happens, use npm ci.

Here is a scenario that might explain things (Verified with NPM 6.3.0)

You declare a dependency in package.json like:

shell
"depA": "^1.0.0"

Then you do, npm install which will generate a package-lock.json with:

shell
"depA": "1.0.0"

Few days later, a newer minor version of "depA" is released, say "1.1.0", then the following holds true:

shell
npm ci # respects only package-lock.json and installs 1.0.0 npm install # also, respects the package-lock version and keeps 1.0.0 installed # (i.e. when package-lock.json exists, it overrules package.json)

Next, you manually update your package.json to:

shell
"depA": "^1.1.0"

Then rerun:

shell
npm ci # will try to honor package-lock which says 1.0.0 # but that does not satisfy package.json requirement of "^1.1.0" # so it would throw an error npm install # installs "1.1.0" (as required by the updated package.json) # also rewrites package-lock.json version to "1.1.0" # (i.e. when package.json is modified, it overrules the package-lock.json)
2024年6月29日 12:07 回复

Use the newly introduced

shell
npm ci

npm ci promises the most benefit to large teams. Giving developers the ability to “sign off” on a package lock promotes more efficient collaboration across large teams, and the ability to install exactly what is in a lockfile has the potential to save tens if not hundreds of developer hours a month, freeing teams up to spend more time building and shipping amazing things.

Introducing npm ci for faster, more reliable builds

2024年6月29日 12:07 回复

Use the npm ci command instead of npm install.

"ci" stands for "clean install".

It will install the project dependencies based on the package-lock.json file instead of the lenient package.json file dependencies.

It will produce identical builds to your team mates and it is also much faster.

You can read more about it in this blog post: https://blog.npmjs.org/post/171556855892/introducing-npm-ci-for-faster-more-reliable

2024年6月29日 12:07 回复

你的答案