package-lock.json 与 package.json

前言

有小伙伴提出:“为什么执行 npm install 时有些包不会安装,每次都得删掉 node_modules 和 package-lock 然后重新安装……”,看到这个问题,我陷入了沉思,闲暇查阅了资料,好好地理了一下思绪。在解答疑惑的同时,先记录几个术语介绍。

版本控制规则

a.b.c

  • a 表示主版本号,b表示次版本号,c 表示补丁更新
  • 当只是简单的修复了 bug, 没有添加任何新功能,或者修改旧功能时, 就更新补丁号 c;
  • 当添加了新的功能, 但没有破坏原有的功能,就更新次版本号 b;
  • 当做了重大修改,导致新版本不兼容旧代码时,就更新主版本号 a

package.json 版本控制举例

  1. 指定版本:比如 “antd”: “3.10.7”或”antd”: “=3.10.7”,表示安装3.10.7的版本
  2. :比如 “antd”: “3.10.7”,表示安装3.10.x的最新版本(不低于3.10.7),但是不安装3.11.x,也就是说安装时不改变大版本号和次要版本号
  3. ^:比如 “antd”: “^3.10.7”,表示安装3.10.7及以上的版本,但是不安装4.0.0,也就是说安装时不改变大版本号

package.json

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
"name": "webpack-test",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"devDependencies": {
"webpack-cli": "^3.3.2"
},
"dependencies": {
"webpack": "^2.0.0"
}
}
  • 生成方式:执行 npm init 命令

  • 主要作用:描述项目及项目所依赖的模块信息

package-lock.json

  • 生成方式:从 npm 5 版本之后只要使用 npm install 命令下载,就会自动生成 package-lock.json 文件。保证我们的应用程序依赖之间的关系是一致的,兼容的;适合多人协作开发时保证每个人的依赖版本是一致的

  • 主要作用:

    1. 描述 node_modules 文件中所有模块的版本信息,模块来源及依赖的小版本信息
    2. 当版本升级,使用 npm install 命令时,会安装 package.json 中指定的大版本的最新版本。如 package.json 中指定版本 "dependencies": { "webpack": "^2.0.0" },则 package-lock.json 会按照 {"webpack": "2.7.0"} 版本升级。在保证大版本号前提下的最新版本。webpack "2.7.0""2.x.x" 的最高版本
    3. 加快了npm install 的速度,因为 package-lock.json 文件中已经记录了整个 node_modules 文件夹的树状结构,同时记录了模块的下载地址

使用yarn同样也会自动生成package-lock.json文件,但是cnpm不会自动生成,并且也不会读取package-lock.json文件,只根据package.json下载依赖

更新依赖

在npm 5.x之前,我们可以直接更改package.json中的版本号,再npm install就可以直接更新了,但是5.x之后由于是根据package-lock.json安装依赖,所以我们只能使用npm install xxx@x.x.x去更新依赖,这样package-lock.json也会同步更新。

package.json 与 package-lock.json

  1. package.json里面定义的是版本范围(比如^1.0.0),具体跑npm install的时候安的什么版本,要解析后才能决定,这里面定义的依赖关系树,可以称之为逻辑树(logical tree)。

  2. node_modules文件夹下才是npm实际安装的确定版本的东西,这里面的文件夹结构我们可以称之为物理树(physical tree)。安装过程中有一些去重算法,所以你会发现逻辑树结构和物理树结构不完全一样。

  3. package-lock.json可以理解成对结合了逻辑树和物理树的一个快照(snapshot),里面有明确的各依赖版本号,实际安装的结构,也有逻辑树的结构。

为什么 package-lock.json 会出现呢?

大多数情况这种向新兼容依赖下载最新库包的时候都没有问题,可是因为npm是开源世界,各库包的版本语义可能并不相同,有的库包开发者并不遵守严格这一原则:相同大版本号的同一个库包,其接口符合兼容要求。这时候用户就很头疼了:在完全相同的一个nodejs的代码库,在不同时间或者不同npm下载源之下,下到的各依赖库包版本可能有所不同,因此其依赖库包行为特征也不同有时候甚至完全不兼容。

因此npm最新的版本就开始提供自动生成package-lock.json功能,为的是让开发者知道只要你保存了源文件,到一个新的机器上、或者新的下载源,只要按照这个package-lock.json所标示的具体版本下载依赖库包,就能确保所有库包与你上次安装的完全一样。

简单的说,就是为了保证协作开发的时候,大家下载的包都是一样的,都是同个版本,同个地址下载。

这就不得不回到文章开头的问题,为什么会要删除 node_modules 和 package-lock 然后重新安装呢?

大佬回答:可能是不同系统导致的, MacOs / linux / windows。不同系统下的包依赖(node-sass)不太一样。执行 npm install 时,package-lock.json 检测 package.json 没变,因此使用 package-lock.json 中的包版本进行安装,不同系统下就出问题了。

似乎,这也是 package-lock.json 的一个争议点呢,网上的信息不是很清晰,自己尚未遇到,后续继续关注这个问题~

参考文章

  1. package-lock.json的作用

  2. package.json和package-lock.json

  3. package-lock.json的作用

  4. npm install 生成的package-lock.json是什么文件?有什么用?