Node 20 下用 npm ci 装依赖,我在 lockfile 上翻过车

上周把一个服务从 Node 16 迁到 Node 20.11,CI 用的是 npm ci。本地 npm install 一切正常,流水线跑第三次构建的时候开始报错,说 package-lock.json 和 package.json 不同步,直接退出。仓库大小不大,node_modules 装完 400MB 左右,依赖树大概 900 个包。

排查下来是我在本地升级了两个小依赖,npm install 自动改了 lockfile 的 lockfileVersion 字段,同时又没提交完整(编辑器里只 add 了 package.json)。CI 上 npm ci 会拿 lockfile 跟 manifest 逐条比对,对不上就拒绝安装,这是它跟 npm install 最大的区别。

我的做法是先把两边对齐,再在 CI 里加一道显式检查:

# 先确认 lockfile 是干净的
npm install --package-lock-only
git diff --exit-code package-lock.json

# CI 里固定版本和缓存键
npm ci --prefer-offline --no-audit --fund=false

缓存那行我单独配了 actions/cache,key 用 hashFiles('**/package-lock.json'),不要用 package.json。有一次图省事用了后者,结果 lockfile 改了缓存没失效,装出来的树跟锁文件不一致,查了半天才发现。

为什么这样做:npm ci 的设计前提就是「锁文件是唯一真相」,它先删 node_modules 再按 lockfile 精确安装,不做版本求解。代价是它对 manifest 和 lockfile 的差异零容忍,任何手动改 package.json 又没同步 lockfile 的操作都会在 CI 炸。反过来这正好是它比 npm install 适合流水线的地方——本地能过、线上装出别的版本,这种事我遇到过不止一次。

哪里会失效:workspaces 项目里,根 lockfile 和子包 manifest 的同步更容易漏;用 --legacy-peer-deps 的项目,npm ci 的行为跟本地 npm install 可能不一致,peer 冲突时它照样会失败。还有私有 registry 场景,lockfile 里记的 resolved 地址如果指向内网镜像,换环境后 npm ci 会卡在拉包上,这时候得看 npm config get registry 是不是对上了。

你们团队是把 lockfile 的 diff 当必过检查,还是只在发布前才管它?

0
赞同度 100% · 0 条评论 · 2 阅读

0 条评论

支持 Markdown · 回复会实时推送给对方

还没有评论,写下第一条。