对于 package-lock.json作用,我们要先来了解下包版本
npm采用semver作为包版本管理规范。此规范规定软件版本由三个部分组成:
除了版本号之外,还有一些版本修饰,后面可以带上数字:
版本匹配
*/x:匹配任意值
1.1.* = >=1.1.0 <1.2.0
1.x = >=1.0.0 <2.0.0
^xxx: 最左侧非0版本号不变,不小于xxx
^1.2.3 = >=1.2.3 <2.0.0 主版本号不变
^0.1.2 = >=0.1.2 <0.2.0 主、次版本号不变
^0.0.2 = = 0.0.2 主、次、补丁版本号都不变
~xxx: 如果列出了次版本号,则次版本号不变,如果没有列出次版本号,则主版本号不变,均不小于xxx
~1.2.3 = >=1.2.3 <1.3.0 主、次版本号不变
~1 = >=1.0.0 <2.0.0 主版本号不变
当我们安装包的时候,会自动添加package-lock.json
文件,那么这个文件的作用是什么呢?在这个问题之前,先来看看npm install
的安装原理:
package-lock.json作用
固定版本
当我们安装包的时候,会自动添加package-lock.json文件,那么这个文件的作用是什么呢?在这个问题之前,先来看看npm install的安装原理:
//package.json
{
"name": "npm",
"version": "1.0.0",
"dependencies": {
"vue": "^2.5.1"
},
"devDependencies": {
"eslint": "^7.0.0"
}
}
有上面一份npm配置文件,当npm install时会安装两个包:vue ^2.5.1,eslint ^7.0.0 ,符合所配置版本的包是一个范围多个,npm会会安装符合版本配置的最新版本。比如:
vue ^2.5.1 = >=2.5.1 <3.0.0, npm会选择安装2.6.13,因为它在匹配版本范围内,且是目前最新的vue2的版本,它不会选择2.5.0和3.0.0。
那么如果只有一份package.json文件,就很可能导致项目依赖的版本不一样。比如开发时候vue2的最新版本是2.6.13,过了几个月项目要上线,部署的时候vue2的最新版本已经是2.7.0了,那么线上就会安装最新的版本。如果2.7.0有一些不兼容2.6.13的地方,或者有bug,那就会导致我们开发的一个经典问题:开发环境没问题,一上线就坏。如果项目是多个人协同开发,甚至会导致开发环境都不一样。
那么我们来看看package-lock.json文件怎么解决这个问题的:
//package-lock.json
{
"name": "npm",
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"vue": {
"version": "2.6.13",
"resolved": "https://registry.nlark.com/vue/download/vue-2.6.13.tgz?cache=0&sync_timestamp=1622664849693&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fvue%2Fdownload%2Fvue-2.6.13.tgz",
"integrity": "sha1-lLLBsx/d8d/MNPKOyEi6jwHqTFs="
},
.....
}
}
我们看到package-lock.json文件里直接记录了vue的固定版本号和下载地址。
npm在执行install的时候,会把每个需要安装的包先在package-lock.json里查找,如果找到并且版本符合package.json的配置范围(在范围内就行,不需要最新),就会直接按照package-lock.json里的地址安装。如果没找到或者不符合范围,则安装原本的逻辑安装(符合版本要求的最新版)。
这样就确保,不管时间过了多久,只要package-lock.json文件不变,npm install安装的包的版本都是一致的,避免代码运行的依赖环境不同。
固定依赖结构
我们的一个项目通常会有很多依赖包,而这些依赖包很可能又会依赖其他的包,那如何来避免重复安装呢?
比如:
//package.json
{
"name": "npm",
"version": "1.0.0",
"dependencies": {
"esquery": "^1.4.0",
"esrecurse": "^4.3.0",
"eslint-scope": "^5.1.1"
}
}
依赖关系如下:
如果按照这个嵌套结构来安装包的话也是可以的,而且npm原来的版本就是这么做的,这样可以保证每个包都安装完整,但是问题是会导致一些包重复安装,如果这个依赖很多的话,重复的数量也会很多。那npm是怎么处理的呢?
npm采用的是用扁平结构,包的依赖,不管是直接依赖,还是子依赖的依赖,都会优先放在第一级。
如果第一级有找到符合版本的包,就不重复安装,如果没找到,则在当前目录下安装。
比如上面的包会被安装成如下的结构:
包安装的数量从开始的8个减少到了6个,虽然还是有重复,但是因为这个json的结构,又是以包名为键名,所以同一级下只能有一个同名的包,就像 estraverse : 5.2.0不能放在外层,因为外层已经有了以estraverse为名的对象:estraverse : 4.3.1。
package-lock.json记录的就是上面的依赖结构(上面只是简写,每一项还包含一些其他的信息,比如下载地址),这也是node_modules里面包的结构。
所以一个项目只要package-lock.json不变,它的依赖结构就不变,而且npm不用重新解析包的结构了,直接从package-lock.json文件就可以安装完整且正确的包依赖,也提高了重新安装的效率。