关于package-lock.json
前言
上篇文章我们了解了package.json,一般与它同时出现的还有一个package-lock.json,这两者又有什么关系呢?下面一起来了解吧。
介绍
package-lock.json它会在 npm 更改 node_modules 目录树 或者 package.json 时自动生成的 ,它准确的描述了当前项目npm包的依赖树,并且在随后的安装中会根据 package-lock.json 来安装,保证是相同的一个依赖树,不考虑这个过程中是否有某个依赖有小版本的更新。
为什么需要package-lock.json
相信跟多人跟我一样会有一个疑问:为什么有了package.json还需要package-lock.json?实际上两者并不是同一时期提出来的,package-lock.json是在npm5之后才提出来的,从上面MDN的介绍来看,它的出现主要是为了解决依赖的版本管理问题。
npm install 执行后,会生成一个node_modules 树,在理想情况下, 希望对于同一个 package.json 总是生成完全相同 node_modules 树。在某些情况下,确实如此。但在多数情况下,npm 无法做到这一点。有以下两个原因:
- 某些依赖项自上次安装以来,可能已发布了新版本 。比如:A 包在团队中第一个人安装的时候是
1.0.5版本,package.json中的配置项为A: '^1.0.5',团队中第二个人把代码拉下来的时候,A 包的版本已经升级成了1.0.8,根据package.json中的semver-range version规范,此时第二个人npm install后 A 的版本为1.0.8,可能会造成因为依赖版本不同而导致的 bug - 针对上面的问题,可能有的小伙伴会觉得把 A 的版本号固定为
A: '1.0.5'不就可以了吗?但是这样的做法其实并没有解决问题, 比如 A 的某个依赖在第一个人下载的时候是2.1.3版本,但是第二个人下载的时候已经升级到了2.2.5版本,此时生成的node_modules树依旧不完全相同 ,固定版本只是固定来自身的版本,依赖的版本无法固定
关于依赖的版本
我们可以先来了解依赖的版本
{
"dependencies": {
"@nestjs/common": "^10.0.0",
"@nestjs/core": "^10.0.0",
}
}
比如我们常见的依赖版本一般长这样,它一般由三部分组成:major.minor.patch,依次为主版本号、次版本号、修补版本号。
主要版本的更改代表了一个破坏兼容性的大变化。 如果用户不适应主要版本更改,则内容将无法正常工作。次要版本的更改表示不会破坏任何内容的新功能。修补版本的更改表示不会破坏任何内容的错误修复。
比如上面我们看到的^10.0.0,主版本号为10、次版本号为0、修补版本号为0,那^表示什么呢?
版本号指定标识符
这个符号其实是用来指定版本范围的,与之对应的有以下符号:
^会匹配最新的大版本依赖包,比如^1.2.3会匹配所有>=1.1.2 <2.0.0的版本,包括1.3.0,但是不包括2.0.0~会匹配最近的小版本依赖包,比如~1.2.3会匹配所有>=1.1.2 <1.2.0的版本,但是不包括1.3.0*安装最新版本的依赖包,比如*1.2.3会匹配x.x.x- 无符号时,比如
1.2.3,那就是将要使用的确切版本,总是会下载这个版本的依赖包
认识package-lock.json
这个文件看起来比package.json又大有复杂,动不动就是上万行代码。
我们可以只安装某一个依赖看看它内部长啥样,比如axios:
{
"name": "demo",
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"asynckit": {
"version": "0.4.0",
"resolved": "https://mirrors.tencent.com/npm/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
},
"axios": {
"version": "1.4.0",
"resolved": "https://mirrors.tencent.com/npm/axios/-/axios-1.4.0.tgz",
"integrity": "sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==",
"requires": {
"follow-redirects": "^1.15.0",
"form-data": "^4.0.0",
"proxy-from-env": "^1.1.0"
}
},
"combined-stream": {
"version": "1.0.8",
"resolved": "https://mirrors.tencent.com/npm/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"requires": {
"delayed-stream": "~1.0.0"
}
},
"delayed-stream": {
"version": "1.0.0",
"resolved": "https://mirrors.tencent.com/npm/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
},
"follow-redirects": {
"version": "1.15.2",
"resolved": "https://mirrors.tencent.com/npm/follow-redirects/-/follow-redirects-1.15.2.tgz",
"integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA=="
},
"form-data": {
"version": "4.0.0",
"resolved": "https://mirrors.tencent.com/npm/form-data/-/form-data-4.0.0.tgz",
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
"requires": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"mime-types": "^2.1.12"
}
},
"mime-db": {
"version": "1.52.0",
"resolved": "https://mirrors.tencent.com/npm/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="
},
"mime-types": {
"version": "2.1.35",
"resolved": "https://mirrors.tencent.com/npm/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"requires": {
"mime-db": "1.52.0"
}
},
"proxy-from-env": {
"version": "1.1.0",
"resolved": "https://mirrors.tencent.com/npm/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
}
}
}
从这里我们可以发现,它的dependencies与package.json不一样,它除了axios之外还包含了一些其它的依赖,实际上这些其它的依赖都是axios的依赖或者是它依赖的依赖...
从上面的介绍中我们也能知道,它实际上描述的是当前项目的依赖树
它有一些与package.json文件中不同的属性,比如:
lockfileVersion
一个整数版本,从1开始,该文档的版本号
resolved
依赖的安装地址,其实就是一个包下载地址
intergrity
表示解压的完整性 Hash 值
dev
表示该模块是否为顶级模块的开发依赖或者是一个的传递依赖关系
requires
依赖包所需要的所有依赖项,对应依赖包 package.json 里
dependencices中的依赖项
npm install策略
当我们每次使用npm install进行依赖安装的时候,它到底是按照什么规则去帮我们下载依赖的呢?
这里其实有好几个版本,但我们只需要了解最新版本就行了。
先看有无lock文件:
如果有,则对比package.json和package-lock.json
- 如果
package-lock.json里包版本号符合package.json要求,则直接获取包信息(如果是从远程拉取,则按照package-lock.json,否则以实际缓存的为准),构建依赖树,(注意这一步只是确定逻辑上的依赖树,并非真正的安装,后面会根据这个依赖结构去下载或拿到缓存中的依赖包);那么接下来就看.npmrc里有没有缓存,如果有缓存文件,则从缓存文件中拉取内容,否则从远程拉取;并更改package-lock。json版本号 - 如果版本号不符合要求,则直接从远程拉取,并更新
package-lock.json中的版本号
如果没有,则:
- 根据
package.json构建依赖树(注意这一步只是确定逻辑上的依赖树,并非真正的安装,后面会根据这个依赖结构去下载或拿到缓存中的依赖包) - 如果缓存中
(.npmrc)有,则优先从缓存中读取,否则从远程读取;注意:(如果是从远程拉取,则按照package.json,否则以实际缓存的为准)
需要注意的是,在使用cnpm install时候,并不会生成 package-lock.json 文件,也不会根据 package-lock.json 来安装依赖,它只会根据 package.json 来安装依赖
场景一
// package.json
"dependencies": {
"vue": "^2.0.0"
}
// package-lock.json
"dependencies": {
"vue": {
"version": "2.7.14",
"resolved": "https://mirrors.tencent.com/npm/vue/-/vue-2.7.14.tgz",
"integrity": "sha512-b2qkFyOM0kwqWFuQmgd4o+uHGU7T+2z3T+WQp8UBjADfEv2n4FEMffzBmCKNP0IGzOEEfYjvtcC62xaSKeQDrQ==",
"requires": {
"@vue/compiler-sfc": "2.7.14",
"csstype": "^3.1.0"
}
}
}
这种情况下package-lock.json指定的2.7.14在^2.0.0指定的范围内,npm install会安装vue2.7.14版本。
场景二
// package.json
"dependencies": {
"vue": "^2.2.0"
}
// package-lock.json
"dependencies": {
"vue": {
"version": "2.1.0",
"resolved": "https://mirrors.tencent.com/npm/vue/-/vue-2.1.0.tgz",
"integrity": "sha1-KTuj76rKhGqmvL+sRc+FJMxZfj0="
}
}
这种情况下package-lock.json指定的2.1.0不在^2.2.0指定的范围内,npm install会按照^2.2.0的规则去安装最新的2.7.14版本,并且将package-lock.json的版本更新为2.7.14。
现在应该能够理解package.json文件是如何做到对依赖进行版本锁定的吧,我们一般在安装依赖时如果不指定版本,那么安装的版本号并不是固定的而是一个最优版本,最优版本会在版本前多了一个^或者~符号
"dependencies": {
"vue": "^2.0.0"
}
但我们的lock文件中肯定是会指定一个固定版本进行安装的,一般是改依赖的符合版本范围的最新版本
"dependencies": {
"vue": {
"version": "2.1.0",
"resolved": "https://mirrors.tencent.com/npm/vue/-/vue-2.1.0.tgz",
"integrity": "sha1-KTuj76rKhGqmvL+sRc+FJMxZfj0="
}
}
至于为什么不直接在package.json中将版本锁定,那是因为你只能指定你安装的依赖的版本,但不能指定你依赖的依赖的版本
package-lock.json什么时候会变?
开发过程中是不是经常遇到这个文件冲突的,自己明明没改这个文件为啥会冲突?那是因为我们的一些操作会影响到该文件的内容,比如:
package-lock.json在npm install的时候会自动生成
- 当我们修改依赖位置,比如将部分依赖从
开发依赖改成生产依赖,虽然整体上的依赖并未改变,但是也会影响package-lock.json中依赖的dev字段
- 如果我们切换
npm镜像时,执行npm install时也会修改package-lock.json,因为它是会记录我们的依赖包地址的(resolved) - 当我们使用
npm install添加或npm uninstall移除包的时候,也会修改package-lock.json - 当我们更新某个包的版本的时候,也会修改
package-lock.json
package-lock.json需要提交到仓库吗?
npm 官网建议:把
package-lock.json一起提交到代码库中,不要 ignore。但是在执行 npm publish 的时候,它会被忽略而不会发布出去。
如何查看依赖安装的版本?
上面我们已经了解到,package.json中保存的依赖版本一般不是一个具体版本,而是一个带有^或~的最优版本,那我们怎么才能知道当前项目依赖安装的具体版本呢?
- 查看
package-lock.json文件,这里保存的是依赖的具体版本 - 从
node_modules文件夹中找到对应依赖的package.json文件,里面的version字段就是该依赖的版本 - 使用
npm list --depth 0查看项目所有的依赖版本

如果这篇文章有帮助到你,️关注+点赞️鼓励一下作者,关注 前端南玖 第一时间获取最新文章~
关于package-lock.json的更多相关文章
- vue.config.json CopyWebpackPlugin 没有生效
本地生效,服务器不生效. 因为是jenkinis构建,没有留意到报错.后来发现错误:ENOENT: no such file or directory, rename 解决方法就是:删除package ...
- 解决npm ERR!Unexpected end of JSON input while paring near (解析附近时JSON输入意外结束)'...."^2.0.0-rc.0","glob"'等npm install错误
摘要 最近更新了一次node,但是更新后npm的命令总是会报 npm WARN deprecated fsevents@2.0.6: Please update: there are crash fi ...
- 详解package-lock.json的作用
目录 详解package-lock.json package-lock.json的作用 版本号的定义规则与前缀对安装的影响 改动package.json后依旧能改变项目依赖的版本 当前项目的真实版本号 ...
- vue-cli中webpack配置详解
vue-cli是构建vue单页应用的脚手架,命令行输入vue init <template-name> <project-name>从而自动生成的项目模板,比较常用的模板有we ...
- vue-cli脚手架中webpack配置基础文件详解
一.前言 原文:https://segmentfault.com/a/1190000014804826 vue-cli是构建vue单页应用的脚手架,输入一串指定的命令行从而自动生成vue.js+wep ...
- Settings-Sync插件源码阅读
一.介绍 请参考官网: https://marketplace.visualstudio.com/items?itemName=Shan.code-settings-sync 二.源码目录详解 Ima ...
- vue-cli 脚手架中 webpack 配置基础文件详解
一.前言 vue-cli是构建vue单页应用的脚手架,输入一串指定的命令行从而自动生成vue.js+wepack的项目模板.这其中webpack发挥了很大的作用,它使得我们的代码模块化,引入一些插件帮 ...
- NPM cache相关
今天下午把package.lock.json用别人的替换了,然后编译一堆报错,这个问题弄了一下午. 总结一下经验: 1.关于npm cache NPM会把所有下载的包保存,放在用户文件夹下面,在我的w ...
- 无缘无故出现npm 解析异常的的问题 解决方案
npm cache clean --force try if false delete package.lock.json try again if false npm set registry ht ...
- 前端的标配:npm是什么及其安装(含cnpm)
前端的标配:npm是什么及其安装 一:npm是什么及其来源 参考来源:npm是干什么的 总结:不需要去相关的网站下载依赖,用一个工具把这些依赖集中起来管理 NPM 的思路大概是这样的: 1)买个服务器 ...
随机推荐
- 2023-05-11:给你一个 m x n 的二进制矩阵 grid, 每个格子要么为 0 (空)要么为 1 (被占据), 给你邮票的尺寸为 stampHeight x stampWidth。 我们想将
2023-05-11:给你一个 m x n 的二进制矩阵 grid, 每个格子要么为 0 (空)要么为 1 (被占据), 给你邮票的尺寸为 stampHeight x stampWidth. 我们想将 ...
- 2022-06-04:给定一个数字n,表示一开始有编号1~n的树木,列成一条直线, 给定一个有序数组arr,表示现在哪些树已经没了,arr[i]一定在[1,n]范围, 给定一个数字m,表示你可以补种多
2022-06-04:给定一个数字n,表示一开始有编号1~n的树木,列成一条直线, 给定一个有序数组arr,表示现在哪些树已经没了,arr[i]一定在[1,n]范围, 给定一个数字m,表示你可以补种多 ...
- vue全家桶进阶之路43:Vue3 Element Plus el-form表单组件
在 Element Plus 中,el-form 是一个表单组件,用于创建表单以便用户填写和提交数据.它提供了许多内置的验证规则和验证方法,使表单验证更加容易. 使用 el-form 组件,您可以将表 ...
- 初等数论——素数,逆元,EXGCD有关
初等数论 素数定义 设整数 \(p\ne 0,\pm 1\) .如果 \(p\) 除了平凡约数以外没有其他约数,那么称 \(p\) 为素数(不可约数). 若整数 \(a\ne 0,\pm 1\) 且 ...
- 从 DevOps 到平台工程:软件开发的新范式
DevOps 是一种将开发和运营结合起来的方法,在应用规划.开发.交付和运营方面将人员.流程和技术结合起来.DevOps 使以前孤立的角色(如开发.IT运营.质量工程和安全)之间进行协调和合作.一直以 ...
- weex 开发APP 多行文本溢出处理
weex中文字溢出不能使用常规的overflow:hidden 如: .text { overflow: hidden; text-overflow: ellipsis; white-space: n ...
- Python数据类型 - 元祖
介绍 元祖和列表都是有序数列,列表是用 [ ],元祖使用() 元祖不同的地方在于创建后不能修改 注意:当元祖中只有一个元素的时候,要加上逗号(一个括号会被当成运算符使用) 比如: (123, ) ...
- python 学习 ---函数(带参数)
函数式编程最重要的是增强代码的重用性和可读性 1 def 函数名(参数): 2 3 ... 4 函数体 5 ... 函数的定义主要有如下要点: def:表示函数的关键字 函数名:函数的名称,日后根据函 ...
- Nucleic Acids Research上关于生物医学分析Galaxy平台在几个独立面上的最新发展。
该平台的官方主服务器拥有超过124000注册用户,每月新注册用户~2000。平均而言,......
本文分享自微信公众号 - 生信科技爱好者(bioitee).如有侵权,请联系 support@oschina.cn 删除.本文参与"OSC源创计划",欢迎正在阅读的你也加入,一起分 ...
- Vue——表单控制、购物车案例、v-model进阶、与后端交互三种方式、箭头函数
表单控制 // 1 checkbox 单选 多选 // 2 radio 单选 <body> <div id="app"> <h1>checkbo ...