一些package-lock.json的小知识

4,637 阅读3分钟

package-lock.json的作用

由于package.json文件中的语义版本锁定,安装源也不固定,我们在协同开发和线上构建时,不同开发者npm i得到的依赖版本可能会有一定差异。而package-lock.json的出现,正是为了保证我们依赖版本的一致性。

对于是否将package-lock.json文件上传到远程仓库,也有许多有趣的讨论,例如package-lock.json 需要写进 .gitignore 吗?

这里讨论的是将该文件上传到远程仓库时,可能遇到的一些问题和解决方法。

package-lock.json的表现

在npm@5.4.2版本后的表现:

  1. 无package-lock.json

    npm i 根据package.json进行安装,并生成package-lock.json

  2. package.json和package-lock.json的版本不兼容

    npm i 会以package.json为准进行安装,并更新package-lock.json

  3. package.json和package-lock.json的版本兼容

    npm i 会以package-lock.json为准进行安装。

关于旧的npm版本的表现,这个回答有比较清楚的解释。

更多特性,也可参考package-lock npm官方文档的相关说明。

npm ci

由于以上1、2点的存在,即使有package-lock.json文件,配合npm i,我们也不能保证线上构建时的依赖版本与本地开发时的一致。

npm ci是类似于npm i的命令,适用于ci时安装依赖。npm cinpm i主要的差异有:

  • 使用npm ci的项目必须存在package-lock.json或npm-shrinkwrap.json文件,否则无法执行(即以上1的情况)
  • 如果package-lock.json或npm-shrinkwrap.json中的依赖与package.json中不一致(即以上2的情况),npm ci会报错并退出,而不是更新lock文件
  • npm ci只会安装整个项目,无法单独安装某个依赖项目
  • 如果项目中已有node_modules,该文件夹会在npm ci执行安装前自动被移除
  • 该命令不会写入package.json或lock文件,安装的行为是完全被固定的。

基于以上几种特性,使用npm ci能够有效防止线上构建的依赖与开发者本地不一致。

可查阅npm文档

如何解决package-lock.json的冲突

package-lock.json文件不由开发者自行写入,在协同开发时,某一方若更新了依赖,很容易产生大量冲突,且难以逐个解决。

  1. npm文档中推荐的两种方式:

    • 5.7.0版本的npm开始,解决package-lock.json的冲突可以通过解决package.json的冲突后,运行 npm install [--package-lock-only] 来完成。npm会自动解析package-lock.json中的冲突,并生成一个有着合理的tree结构,且包含了两个分支的所有依赖的lock文件。
    • 文档中还提到了一个npm-merge-driver工具,可以帮助开发者解决package-lock.json的冲突。
  2. 至于旧版本的npm,可以尝试对于package-lock.json文件,忽略掉冲突,并重新npm i。以下是一些可行的具体操作。

    • 在vscode上选择Accept All Incoming/Current Changes后npm i
    • 将package-lock.json文件checkout到之前某个commit的状态,git checkout [commitId] -- path/to/package-lock.json,再npm i

    最好将文件重置到非自己开发分支的状态,便于合并之后的验证。例如,对于将master合进自己开发的特性分支的情况(如git pull origin master),对于冲突,选择Accept All Incoming。