我最近刚升级到npm@5。我现在有一个包锁。包含package.json中的所有内容的Json文件。我希望,当我运行npm install时,依赖版本将从锁文件中提取,以确定应该在我的node_modules目录中安装什么。奇怪的是,它实际上最终修改和重写了我的包锁。json文件。
例如,锁文件的typescript被指定为2.1.6版本。然后,在执行npm install命令后,版本被更改为2.4.1。这似乎违背了锁文件的全部目的。
我错过了什么?我如何让npm尊重我的锁文件?
我最近刚升级到npm@5。我现在有一个包锁。包含package.json中的所有内容的Json文件。我希望,当我运行npm install时,依赖版本将从锁文件中提取,以确定应该在我的node_modules目录中安装什么。奇怪的是,它实际上最终修改和重写了我的包锁。json文件。
例如,锁文件的typescript被指定为2.1.6版本。然后,在执行npm install命令后,版本被更改为2.4.1。这似乎违背了锁文件的全部目的。
我错过了什么?我如何让npm尊重我的锁文件?
当前回答
编辑:“锁”这个名字是一个棘手的名字,它的NPM试图赶上Yarn。这不是一个锁定的文件。包中。Json是一个用户固定的文件,一旦“安装”将生成node_modules文件夹树,然后该树将被写入package-lock.json。所以你看,它是另一种方式-依赖版本将从包拉。Json和包锁。Json应该被称为package-tree.json
(希望这能让我的回答更清楚,在这么多的反对票之后)
一个简单的答案:打包。Json像往常一样有你的依赖项,而package-lock。Json是“一个精确的,更重要的是可复制的node_modules树”(取自NPM文档本身)。
至于这个棘手的名字,它的NPM试图赶上Yarn。
其他回答
更新3:正如其他答案所指出的,npm ci命令在npm 5.7.0中被引入,作为在ci环境中实现快速和可复制构建的额外方式。更多信息请参阅文档和npm博客。
更新2:更新和澄清文档的问题是GitHub issue #18103。
更新1:下面描述的行为在npm 5.4.2中得到了修复:当前预期的行为在GitHub issue #17979中概述。
原答案(5.4.2之前):包锁的行为。Json在NPM 5.1.0中被改变了,在第16866期讨论过。你观察到的这种行为显然是npm 5.1.0版本的意图。
就是那个包裹。Json可以覆盖包锁。每当在package.json中发现一个依赖项的新版本时,就调用Json。如果你想有效地固定依赖项,你现在必须指定不带前缀的版本,例如,你需要把它们写成1.2.0而不是~1.2.0或^1.2.0。然后组合包装。Json和包锁。Json将产生可复制的构建。需要明确的是:package-lock。Json单独不再锁定根级依赖!
无论这个设计决定是好是坏是有争议的,在GitHub上的17979号问题中,有一个正在进行的讨论。(在我看来,这是一个值得怀疑的决定;至少这个名字锁不再适用了。)
另一个边注:对于不支持不可变包的注册表也有限制,例如当你直接从GitHub而不是npmjs.org提取包时。有关进一步的解释,请参阅包锁的文档。
这个问题在npm v5.4.2中被修复了
https://github.com/npm/npm/issues/17979
(向下滚动到线程中的最后一条评论)
更新
在5.6.0中修正。在5.4.2中有一个跨平台的错误,导致这个问题仍然发生。
https://github.com/npm/npm/issues/18712
更新2
请看我的回答: https://stackoverflow.com/a/53680257/1611058
NPM ci是你现在安装现有项目时应该使用的命令。
简短的回答:
NPM安装荣誉包锁。Json,如果它满足package.json的要求。 如果它不满足这些要求,则更新包并覆盖包锁。 如果你希望安装失败,而不是覆盖包锁发生时,使用npm ci。
下面是一个可能解释这些事情的场景(经过NPM 6.3.0验证)
在包中声明一个依赖项。json:
"depA": "^1.0.0"
然后执行npm install,它会生成一个包锁。json:
"depA": "1.0.0"
几天后,“depA”的一个更新的小版本发布了,比如“1.1.0”,那么下面的情况是成立的:
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)
接下来,手动更新包。json:
"depA": "^1.1.0"
然后重新运行:
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)
你可能会遇到这样的情况:
"typescript":"~2.1.6"
在你的包裹里。NPM将它更新到最新的小版本,在你的例子中是2.4.1
Edit: Question from OP But that doesn't explain why "npm install" would change the lock file. Isn't the lock file meant to create a reproducible build? If so, regardless of the semver value, it should still use the same 2.1.6 version. Answer: This is intended to lock down your full dependency tree. Let's say typescript v2.4.1 requires widget ~v1.0.0. When you npm install it grabs widget v1.0.0. Later on your fellow developer (or CI build) does an npm install and gets typescript v2.4.1 but widget has been updated to widget v1.0.1. Now your node module are out of sync. This is what package-lock.json prevents. Or more generally: As an example, consider package A: { "name": "A", "version": "0.1.0", "dependencies": { "B": "<0.1.0" } } package B: { "name": "B", "version": "0.0.1", "dependencies": { "C": "<0.1.0" } } and package C: { "name": "C", "version": "0.0.1" } If these are the only versions of A, B, and C available in the registry, then a normal npm install A will install: A@0.1.0 -- B@0.0.1 -- C@0.0.1 However, if B@0.0.2 is published, then a fresh npm install A will install: A@0.1.0 -- B@0.0.2 -- C@0.0.1 assuming the new version did not modify B's dependencies. Of course, the new version of B could include a new version of C and any number of new dependencies. If such changes are undesirable, the author of A could specify a dependency on B@0.0.1. However, if A's author and B's author are not the same person, there's no way for A's author to say that he or she does not want to pull in newly published versions of C when B hasn't changed at all.
OP Question 2: So let me see if I understand correctly. What you're saying is that the lock file specifies the versions of the secondary dependencies, but still relies on the fuzzy matching of package.json to determine the top-level dependencies. Is that accurate? Answer: No. package-lock locks the entire package tree, including the root packages described in package.json. If typescript is locked at 2.4.1 in your package-lock.json, it should remain that way until it is changed. And lets say tomorrow typescript releases version 2.4.2. If I checkout your branch and run npm install, npm will respect the lockfile and install 2.4.1.
关于package-lock.json的更多信息:
package-lock。当NPM修改node_modules树或package.json时,Json会自动生成。它描述了生成的确切的树,以便后续安装能够生成相同的树,而不考虑中间依赖项更新。
该文件旨在提交到源存储库中,并用于各种目的:
Describe a single representation of a dependency tree such that teammates, deployments, and continuous integration are guaranteed to install exactly the same dependencies. Provide a facility for users to "time-travel" to previous states of node_modules without having to commit the directory itself. To facilitate greater visibility of tree changes through readable source control diffs. And optimize the installation process by allowing npm to skip repeated metadata resolutions for previously-installed packages.
https://docs.npmjs.com/files/package-lock.json
我发现在npm 5.7.1的新版本中加入了新的命令npm ci,它将从package-lock安装。json只
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.