npm install 和 lockfile 的一个误区

420 阅读3分钟

pexels-pengwhan-1767434.jpg

欢迎大家关注公众号『JavaScript与编程艺术』高质量文章优先公众号发布。

首先提个问题,如果你能自信回答出来就无需阅读本文了:

某包存在 package-lock.json,当项目 npm install 该依赖,请问会按照其 package-lock.json 指定的版本安装依赖吗?

例如包 A 依赖 C@1.0.0 而且锁了版本,当 C 升级到 1.0.1,项目 P 再次安装相同版本的 A,此时 C 仍然会是 1.0.0 吗?

答案

视情况而定。

  • 首次安装:A,C 将会是更新后 1.0.1。即使项目 P 和包 A 都有锁版本
  • 二次安装:P 如果存在 lockfile,则 C 会保留 1.0.0。否则会更新到 1.0.1

本文将介绍为什么 A 已经锁定了版本为何仍然会更新。

为什么依赖的 package-lock.json 不生效

那是不是发布产物没有 lock file 导致的,我们尝试通过 package.json files 指定发布产物必须增加 package-lock.json 和 yarn.lock。

// package.json
{
  "files": [ "package-lock.json", "yarn.lock", "dist" ]
}

但出现了新问题:package-lock.json 仍然会没有打包到产物中(小技巧可以通过 npm publish --dry-run 查看产物而无需真实发布),为什么呢?

The difference is that package-lock.json cannot be published, and it will be ignored if found in any place other than the root project.

docs.npmjs.com/cli/v7/conf…

这是从官方文档引用的原文,但说的不是很清楚,stackoverflow 上也有一些讨论

翻阅了诸多文档后,在这篇文章中找到了解释:

image.png

What's the issue in publishing package-lock.json

lockfile 不应该被发布的原因是因为这不会有任何作用。npm 会忽略任何不在项目根目录下的 package-lock.json 文件,因为锁定依赖项除了在项目本身之外的任何地方都没有意义。

没有任何出错的危险,只是发布它是毫无意义的。

可以得出两点:

  1. npm install 只会寻找根目录的 package-lock.json。故即使我们发布产物包含了 package-lock.json 也没用。
  2. npm install 寻找依赖的 package-lock.json 没有意义,现在的模式没有任何风险。

我们需要辩证的看,第一点没问题是 npm 的机制,第二点并非没有意义而且现在是存在风险的。

设想一个这样的 case

我开发了一个包 A@1.0.0, 依赖了 B@2.0.0, 它依赖了 C@^1.0.0. 在发布的那一刻代码依赖是 A -> B@2.0.0 -> C@1.0.0。我发布之前本地测试通过了,但是此后 C 发布了 1.0.2, 却引起了破坏性的变更,即使A已经锁定了版本,但是安装过程变成了 A@1.0.0 -> B@2.0.0 ->C@1.0.1,而我只测试了 C@1.0.0 但是却被其他项目安装的时候自动更新成 C@1.0.1,自然别人安装同样版本的 A@1.0.0 就挂了。

这其实是有现实案例的,即使包 A 锁定了版本也会出现 C 被自动更新,案例见 react-i18next 从 14.1.2 升级到 14.1.3,我的项目跑不起来了 -_-||

怎么锁定依赖的依赖

可以让 A 安装严格相等版本。

.npmrc 增加以下配置,安装无需加任何 flag,只需 npm install xx

save=true
save-exact=true

安装时会默认添加 --save-exact-E 进一步锁定版本。因为通过 lockfile 锁定的版本,在被其他项目 install 仍然会更新依赖。

-        "react-i18next": "^14.1.1",
+        "react-i18next": "14.1.2"

其他方案:采用 yarn#resolutionsnpm#overrides。相对比较麻烦得逐个包设置。

问题回顾

本文提出了一个“反常识”的现象,锁版本对于库或包来说“不起作用”。因为被安装的时候 npm 只会寻找自己根目录package-lock.json

该问题在首次安装时候会出现,其实影响还好,因为首次安装一定会测试到位。但是有个不小的困扰我们debug的问题是同一个包不同时间段被安装可能出现问题,即使这个包作者已经锁了版本,如果我们理解了第一点就能快速做出 fix 措施。