我刚刚升级到 npm@5。我现在有一个 package-lock.json 文件,其中包含 package.json 中的所有内容。我希望,当我运行 npm install
时,将从锁定文件中提取依赖版本以确定应该在我的 node_modules 目录中安装什么。奇怪的是,它实际上最终修改和重写了我的 package-lock.json 文件。
例如,锁定文件的 typescript 指定为版本 2.1.6。然后,在 npm install
命令之后,版本更改为 2.4.1。这似乎违背了锁定文件的全部目的。
我错过了什么?如何让 npm 真正尊重我的锁定文件?
npm install
时,我的 package-lock.json
会重新生成。这闻起来像一个 npm 错误。您使用自己的注册表吗?
--no-save
防止更改锁定文件,但它不会影响 OP 提到的愚蠢的一级依赖项升级。
npm i
时没有更改任何内容,并且我的 package-lock.json
已修改(requires
中所有包下的版本都已更改)。它似乎是有意而不是破坏任何东西?更多信息here
更新 3: 正如其他答案所指出的那样,在 npm 5.7.0 中引入了 npm ci
命令,作为在 CI 上下文中实现快速且可重现的构建的另一种方法。有关详细信息,请参阅 documentation 和 npm blog。
更新 2: 更新和澄清文档的问题是 GitHub issue #18103。
更新 1: 下面描述的行为已在 npm 5.4.2 中得到修复:当前预期的行为在 GitHub issue #17979 中进行了概述。
原始答案: package-lock.json
的行为在 npm 5.1.0 中已更改,如 issue #16866 中所述。您观察到的行为显然是 npm 从 5.1.0 版开始的。
这意味着只要在 package.json
中为依赖项找到较新版本,package.json
就可以覆盖 package-lock.json
。如果您想有效地固定您的依赖关系,您现在必须指定不带前缀的版本,例如,您需要将它们写为 1.2.0
而不是 ~1.2.0
或 ^1.2.0
。然后 package.json
和 package-lock.json
的组合将产生可重现的构建。需要明确的是:单独的 package-lock.json
不再锁定根级别的依赖关系!
这个设计决定是否好是有争议的,在 issue #17979 中的 GitHub 上存在着由这种混淆引起的持续讨论。 (在我看来,这是一个值得商榷的决定;至少 lock
这个名字不再适用了。)
另一个注意事项:对于不支持不可变包的注册表也有限制,例如当您直接从 GitHub 而不是 npmjs.org 拉包时。请参阅 this documentation of package locks 了解更多说明。
我发现会有一个带有新命令 npm ci
的新版本 npm 5.7.1,它只能从 package-lock.json
安装
新的 npm ci 命令仅从您的锁定文件安装。如果你的 package.json 和你的 lock-file 不同步,那么它会报错。它通过丢弃你的 node_modules 并从头开始重新创建它来工作。除了保证您只会获得锁定文件中的内容之外,当您不从 node_modules 开始时,它也比 npm install 快得多(2x-10x!)。正如您可能从名称中看到的那样,我们希望它对持续集成环境来说是一个巨大的福音。我们还希望通过 git 标签进行生产部署的人们会看到重大收获。
npm ci
之前,文档说 “确保您有包锁和最新的安装:npm install
”。 npm install
不会覆盖 package-lock.json 文件吗?
npm
仅更改锁定文件如果需要这样做,以满足 packages.json 中的规范。因此,如果包过去说 thatpackage: 1
,而 lock 说 ..: 1.0.4
,则开发人员可以编辑说 thatpackage: 2
- 这将强制 lock 文件更改,因为 1.0.4
与新指定的范围不兼容。如果不更改 packages.json
,将保持锁定在确切的版本,直到删除锁定文件。 [如果没有保持锁定,并且没有更改 packages.json,请提交错误报告。]
简短的回答:
npm install 只有在满足 package.json 的要求时才会尊重 package-lock.json。
如果它不满足这些要求,则更新包并覆盖包锁。
如果您希望安装失败而不是在发生这种情况时覆盖包锁定,请使用 npm ci。
这是一个可以解释事情的场景(使用 NPM 6.3.0 验证)
您在 package.json 中声明一个依赖项,例如:
"depA": "^1.0.0"
然后你这样做,npm install
这将生成一个 package-lock.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)
接下来,您手动将 package.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)
npm install
将使用来自 package-lock.json
的锁定版本,除非它不满足 package.json
,在这种情况下它会安装 package.json 并相应地重建 package-lock.json。如果您更改了您的 package.json
,使现有的包锁仍然满足更新后的 package.json
,它将继续使用该 package-lock
npm install
什么都不做,不管 package-lock.json 是什么。即使有可用的更新与 package.json 中指定的 semver 匹配,我们也必须显式更新包。至少这是我多年来的经验。
node_modules
内的版本满足 package.json
的范围,并且没有 package-lock.json
文件,则 npm 在运行 npm install
时不会更新模块。我想这很好,因为您可以使用 npm update
(或最新的 npm-check
)来更新依赖项,并且对于某人只是向 package.json
添加一个条目并且不希望不相关的包更新自己的情况,这种行为会更快到满足 sem-ver 范围的最新版本。
使用新推出的
npm ci
npm ci 承诺给大型团队带来最大的好处。让开发人员能够在包锁上“签字”可以促进大型团队之间更有效的协作,并且能够准确安装锁文件中的内容有可能每月节省数十甚至数百小时的开发时间,从而解放团队花更多的时间建造和运输令人惊奇的东西。
Introducing npm ci
for faster, more reliable builds
npm ci
,并且仅在更新或安装新软件包时使用 npm install
。
node_modules
目录并在本地重建,即使那是一个空但重要的符号链接。 :(
npm ci
的改进,我预计他们将非常不愿意引入任何可能降低相当不常见用例的性能的东西。您可能想查看 pnpm.js.org,尽管它使用硬链接来减少磁盘使用量。
使用 npm ci
命令代替 npm install
。
“ci”代表“全新安装”。
它将基于 package-lock.json 文件而不是宽松的 package.json 文件依赖项安装项目依赖项。
它将为您的队友生成相同的构建,并且速度也更快。
您可以在这篇博文中了解更多信息:https://blog.npmjs.org/post/171556855892/introducing-npm-ci-for-faster-more-reliable
ci
指“持续集成”,如宣布命令的文档和博客文章中所述:blog.npmjs.org/post/171556855892/…
node_modules
文件夹并从头开始重新创建它。真的快很多吗? npm install
是否也会删除 node_modules
文件夹?
npm install
在运行时必须解决所有包依赖项。 npm ci
只是“获取这些确切模块”的购物清单。
ci
实际上代表 clean install
。
看来此问题已在 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 i
时修改我的 package-lock.json。例如,当我在不支持 fsevents
的机器上 npm i
时删除模块 fsevents
,然后在支持的机器上再次添加一个 npm i
时重新添加模块。
package-lock.json
中看到与 npm@5.5
相同的 fsevents
。如果你还没有打开一个问题,我会的。
将来,您将能够使用 --from-lock-file
(或类似的)标志从 package-lock.json
安装 only 而无需修改它。
这对于可重复构建很重要的 CI 等环境很有用。
请参阅 https://github.com/npm/npm/issues/18286 以了解该功能的跟踪。
npm ci
,它也处理你的问题。
可能你应该使用这样的东西
npm ci
如果您不想更改软件包的版本,则不要使用 npm install
。
根据官方文档,npm install
和 npm ci
都安装了项目所需的依赖项。
主要区别在于,npm install 确实安装了以 packge.json 作为参考的包。在 npm ci 的情况下,它确实安装了以 package-lock.json 作为参考的包,确保每次安装确切的包。
你可能有类似的东西:
"typescript":"~2.1.6"
在您的 package.json
中,哪个 npm 更新到最新的次要版本,在您的情况下是 2.4.1
编辑:来自 OP 的问题 但这并不能解释为什么“npm install”会更改锁定文件。锁定文件不是要创建可重现的构建吗?如果是这样,无论 semver 值如何,它仍应使用相同的 2.1.6 版本。答:这是为了锁定您的完整依赖关系树。假设 typescript v2.4.1 需要小部件 ~v1.0.0。当您 npm install 时,它会抓取小部件 v1.0.0。稍后,您的开发人员(或 CI 构建)执行 npm 安装并获取 typescript v2.4.1,但小部件已更新为小部件 v1.0.1。现在你的节点模块不同步了。这就是 package-lock.json 所阻止的。或更一般地说:例如,考虑包 A:{“name”:“A”,“version”:“0.1.0”,“dependencies”:{“B”:“<0.1.0”}} 包 B : { "name": "B", "version": "0.0.1", "dependencies": { "C": "<0.1.0" } } 和包 C: { "name": "C", "version": "0.0.1" } 如果这些是注册表中唯一可用的 A、B 和 C 版本,那么正常的 npm install A 将安装:A@0.1.0 -- B@0.0.1 - - C@0.0.1 但是,如果 B@0.0.2 已发布,则新的 npm install A 将安装: A@0.1.0 -- B@0.0.2 -- C@0.0.1 假设新版本已发布不修改 B 的依赖项。当然,新版本的 B 可以包含新版本的 C 和任意数量的新依赖项。如果不希望进行此类更改,则 A 的作者可以指定对 B@0.0.1 的依赖关系。但是,如果 A 的作者和 B 的作者不是同一个人,那么 A 的作者就没有办法在 B 完全没有变化的情况下说他或她不想拉入新发布的 C 版本。
OP 问题 2:所以让我看看我是否理解正确。你说的是lock文件指定了二级依赖的版本,但还是依赖package.json的模糊匹配来确定顶级依赖。那准确吗?答:不会。package-lock 会锁定整个包树,包括 package.json 中描述的根包。如果 typescript 在您的 package-lock.json 中被锁定为 2.4.1,它应该保持这种状态,直到它被更改。让我们说明天打字稿发布版本 2.4.2。如果我签出你的分支并运行 npm install,npm 将尊重锁定文件并安装 2.4.1。
更多关于 package-lock.json
:
package-lock.json 会为 npm 修改 node_modules 树或 package.json 的任何操作自动生成。它描述了生成的确切树,以便后续安装能够生成相同的树,而不管中间依赖项更新如何。
该文件旨在提交到源存储库中,并用于各种目的:
描述依赖关系树的单一表示,以保证团队成员、部署和持续集成安装完全相同的依赖关系。为用户提供“时间旅行”到 node_modules 先前状态的工具,而无需提交目录本身。通过可读的源代码控制差异来促进对树更改的更大可见性。并通过允许 npm 跳过以前安装的包的重复元数据解析来优化安装过程。
https://docs.npmjs.com/files/package-lock.json
package-lock.json
被拉下,然后我们运行 npm install
,但 package-lock.json
文件被修改,我们必须执行重置,然后才能拉下下一个更改。
编辑:“锁”这个名字是一个棘手的问题,它的 NPM 试图赶上 Yarn。它不是任何锁定的文件。 package.json
是用户固定文件,一旦“安装”将生成 node_modules 文件夹树,然后该树将写入 package-lock.json
。所以你看,它反过来 - 依赖版本将一如既往地从 package.json
中提取,并且 package-lock.json
应该被称为 package-tree.json
(希望这让我的回答更清楚,经过这么多的反对票)
一个简单的答案:package.json
像往常一样拥有您的依赖关系,而 package-lock.json
是“一个精确的,更重要的是可重现的 node_modules 树”(取自 npm docs itself)。
至于棘手的名字,它的 NPM 试图赶上 Yarn。
在他们的 github 页面上有一个未解决的问题:https://github.com/npm/npm/issues/18712
当开发人员使用不同的操作系统时,这个问题最为严重。
Npm install 检测对 package.json 文件所做的任何更改以相应地反映依赖项列表。
前任。如果用户添加或删除了新的依赖项,则构建将下载或删除本地计算机中的依赖项。我们可以将其与 java 中的 .m2 存储库进行比较,其中 maven 不断跟踪 pom.xml 文件以更新依赖项。
package-lock.json 是内部进程在运行时使用的 package.json 的副本,唯一的区别是 package-lock.json 对用户是只读的。
npm update
是为了什么? :o 我有同样的感觉,npm install
更新了 deps,但我不想相信它.. 但似乎这是可悲的事实.. 无论如何仍然可以选择使用npm shrinkwrap
来锁定 deps,但绝对名称 package-lock 不正确,因为它不会冻结,也不会锁定依赖项..