本地 npm ci 成功,CI 锁文件校验失败:比较 legacy-peer-deps
锁文件存在仍报 in sync 或 Missing 时,核对 npm 版本和依赖树配置;统一项目策略后再审查锁文件,保留 peer 兼容性检查。
本地 npm ci 能安装,同一提交在 CI 却提示 package.json 与 package-lock.json 不一致,并列出缺失依赖。锁文件确实已经提交时,要比较生成锁文件的配置:本地开启了 legacy-peer-deps,CI 使用默认值,就可能按不同的依赖树规则校验。
本文针对 npm 7 及之后的 peerDependencies 处理方式,按当前 npm 文档说明排查。不同版本的错误文字可能包含 can only install packages、in sync 或 Missing;这些文本本身不能证明就是 legacy 配置问题。
先确认 CI 看到的是同一个项目
核对 CI 的工作目录、提交版本,以及实际安装的 package.json 和 package-lock.json。多项目仓库可能进入了另一个子目录;只有 yarn.lock 的项目,也不满足 npm ci 的 npm 锁文件要求。没有锁文件或锁文件存在 JSON 语法错误时,应先解决那个问题。
然后在本地和 CI 的项目目录分别查看以下只读信息:
node --version
npm --version
npm config get legacy-peer-deps
npm config get userconfig
npm config get globalconfig
比较实际 npm 版本,而不只比较 Node.js 的大版本。legacy-peer-deps 可能来自项目 .npmrc、用户或全局配置,也可能由命令行参数、CI 环境变量覆盖。旧机器的个人设置不会因为提交了锁文件就自动传到 CI。
如果两边该值相同,继续查其他影响依赖树的选项、版本差异或真实锁文件不一致,不要重复添加 legacy 参数。只确认配置文件路径即可;排查配置时避免把包含仓库令牌的整份 .npmrc 输出到公开日志。
项目确实需要 legacy 模式时,统一生成和安装规则
legacy-peer-deps 会在构建依赖树时忽略 peerDependencies 约束。项目明确采用这种兼容策略时,生成锁文件和 npm ci 应使用一致的选项;把它写成项目配置,比依赖某台开发电脑的个人设置更可控。
当前 npm 的项目范围设置示例是:
npm config set legacy-peer-deps=true --location=project
修改前保留原项目配置及锁文件,确认没有同名配置被更高优先级覆盖。检查新 .npmrc 的差异,只提交团队需要的配置,不提交认证令牌。CI 进入相同项目目录后,再确认实际生效值。
这是对既有兼容策略的延续,会跳过部分依赖契约检查。安装成功不证明这些依赖组合在运行时兼容,还要执行项目已有的构建和关键功能检查。它也不同于 --omit=peer,后者主要控制磁盘上的安装内容,不能拿来替代依赖树解析规则。
legacy 是意外设置时,按正常规则更新锁文件
如果项目本来不需要 legacy 模式,应先查明错误配置来自哪里。不要未经检查删除整份用户配置;其中可能还有其他项目需要的私有仓库设置。
在团队确定的 npm 版本和项目配置下重新解析锁文件。例如,只更新锁文件的命令可以写成:
npm install --package-lock-only --legacy-peer-deps=false
它会改变 package-lock.json。检查依赖版本和结构差异,再在独立工作目录中验证 npm ci 和项目功能。如果出现 peer 冲突,应按包声明核对兼容版本;不要又用 --force 跳过检查,最后留下第二套无人知晓的规则。
需要回退时一起恢复此前审定的项目配置、锁文件和相关依赖声明,而不是只恢复其中一个。CI 每次先执行 npm install 再执行 npm ci,会在安装时重写待验证的锁文件,掩盖差异,不应当作可重复安装的长期方案。
恢复标准
使用同一提交,在明确版本与配置的干净目录中运行 npm ci,不再出现相同依赖树校验错误;安装过程不应改写 package.json 或锁文件。注意 npm ci 会移除已有 node_modules 后安装,不要在存有未备份手工修改的目录中验证。
最后确认构建和关键功能通过。若仍失败,保留这次实际版本、有效配置和第一条具体缺失或冲突信息,继续查锁文件生成规则;删除缓存或反复删除锁文件并不能解释本地与 CI 为什么不同。


