0、目的
- 确定依赖的范围,package-lock.json将这个范围精确到具体版本。主要是为了解决在各个环境中得到确定的node_modules,主要是为了解决在各个环境中得到确定的node_modules。
- 如果只依赖package.json(因为该文件声明的是直接依赖的范围),它无法将直接依赖固定在某个特定版本,也无法声明依赖的依赖。
- 所以需要引入package-lock.json文件来达到我们固定node_modules的目的。
1、package.json
package.json确定当前项目直接依赖的包(例如:dependencies和devDependencies)版本的范围(例如:^1.0.0表示的是大于等于1.0.0小于2.0.0),所以只依赖package.json管理包会有两个缺点:
- 同一份package.json安装的依赖版本可能不同,如果依赖包有小版本更新并且引入了bug会导致重新装包的项目报错。
- package.json中声明的只是直接依赖,依赖的依赖无法通过package.json控制。例如:项目依赖包A,包A依赖包B,包A的版本可以通过package.json中固定版本号的形式固定下来(A: 1.0.0),但是A的依赖B的版本号可能是^2.0.0,这样包B的版本还是无法固定。
2、package-lock.json解决package痛点
package-lock.json文件内容是node_modules文件夹中包结构的快照,npm install 时会根据这份快照生成一模一样的node_modules,所以确保了一份package-lock.json在任何机器,任何时间生成的node_modules都一样,避免了只依赖package.json产生的两个问题。
3、package-lock.json和package.json配合生成node_modules的步骤如下:
- npm7之后的版本生成的package-lock是可信的。
- 如果只有一个package.json并且执行了npm i 我们将会生成package-lock.json文件。
- 如果针对package.json和package-lock.json执行npm i,后者(lock)永远不会更新,即使package.json中依赖的包有更新的版本
- 如果你手动编辑了package.json中依赖包版本到不同版本范围并且执行了npm i,并且这个版本范围和package-lock中的不兼容,之后会更新package-lock中的版本为兼容package.json内的版本。之后npm i的运行和上面两条的描述一致。
4、package-lock.json改变的可能原因
- 手动编辑package.json中依赖包后重新install。
- 将项目依赖改为开发依赖,或者相反后重新install。
- npm registry 的修改后重新npm install,会引起package-lock.json文件中resolved字段的修改,即使包版本一致。
- 新增、删除和更新包后重新install。
5、lock文件生成逻辑
在包版本没有冲突的情况下会将依赖的依赖平铺,如果有冲突则会放到依赖的依赖内部。
例如:a 依赖 b,b 依赖 c,在node_modules中的结构是
|- a@1.0.0
|- b@1.0.0
|- c
如果项目依赖了b@2.0.0:
|- a@1.0.0
|—|-b@1.0.0
|- b@2.0.0
|- c
如果更新依赖,则依赖的依赖同样会更新。例如a发布了版本@1.0.1,b也发布了@1.0.1。npm install a@1.0.1则会变成
|- a@1.0.1
|—|-b@1.0.1
|- b@2.0.0
|- c
6、npm ci 不会修改package-lock.json的装包命令
- 项目必须存在package-lock.json文件或者npm-shrinkwrap.json文件
- 如果如果package lock中的依赖和package.json中的依赖不匹配,npm ci将会报错退出,而不是更新package lock文件
- npm ci 只能一次安装一个项目:这个命令不能添加单独依赖
- 如果node_modules文件夹已经提供,在npm ci 开始安装前它将会被自动移除
- 该命令绝不会写package.json文件和如何package-locks文件:安装本质上是冻结的。
F、问题和解决方案
package-lock.json冲突怎么办?
从稳定的分支checkout package-lock.json,再重新npm install生成一份新的package-lock.json。
想回退package-lock.json中的依赖的依赖版本怎么办?
在项目中直接install依赖的包对应的版本 生成对应的lock文件,在将其从package.json中去除,即可将依赖的依赖版本进行回退。当然回退的版本需要符合版本约束。