依赖管理的目标
1、管理依赖
项目依赖资源一版不会提交到git,只需要声明依赖,使用的时候去下载即可。git上只保存对依赖的“声明”。
2、管理更新
依赖的资源有更新,如何自动跟新到项目中(尤其是bug类的修复版本)。
npm版本号采用语义化的版本声明方式(semver):
版本格式:主版本号.次版本号.修订号,版本号递增规则如下:
- 主版本号:当你做了不兼容的 API 修改,
- 次版本号:当你做了向下兼容的功能性新增,
- 修订号:当你做了向下兼容的问题修正。
- 有时候为了表达更加确切的版本,还会在版本号后面添加标签或者扩展,来说明是预发布版本或者测试版本等
理论上,如果所有的npm包都能采用semver方式管理版本,在项目中对依赖的声明只需要将依赖的npm包主版本号固定即可(npm默认的处理方式就是如此)。但是理想很丰满,现实很骨干,并不是所有npm包都能遵守这个规范,因此可能导致在某个时间再次安装依赖时,存在部分项目所依赖的npm包不向下兼容,导致的项目报错。因此固定依赖的npm包的版本(包括直接依赖和间接依赖)成为一种需求。
package.json对依赖的声明
package.json中的dependencies和devDependencies字段声明了项目的直接依赖资源,声明格式如下:
"chalk": "^2.3.2"
key值表示npm包名,value指定版本信息,版本信息支持三种语法:
测试版本号计算可以到semver计算器测试
| 语法 | 示例 | 说明 | 设置方式 |
|---|---|---|---|
| ^ | ^1.1.1 | 表示安装版本1.1.1到2.0.0(不包括2.0.0)之间的最新版本,即只控制主版本 | (默认)npm config set save-prefix='^' |
| ~ | ~2.2.2 | 表示安装2.2.2到2.3.0(不包括2.3.0)之间的最新版本,即控制主版本和次版本 | npm config set save-prefix='~' |
| xxx.xxx.xxx | 3.3.3 | 固定版本号 | |
| >,<,<=,>=,- | >4.4.4 | 指定安装版本范围,如4.4.1 - 4.5.1(注意“-”两侧的空格)表示4.4.1<= 版本号 <=4.5.1,等价于>=4.4.1<=4.5.1 | |
| || | ^2 <2.2 || > 2.3 | 多个条件组合 | |
由上表可知,默认情况下在不同的时期执行npm install安装的包可能只有主版本号相同,有潜在运行不一致的风险。就算在package.json中使用固定版本的方式声明版本号,也只能解决直接依赖npm包版本问题,间接依赖的npm包还是有可能存在不一致情况。
使用npm shrinkwrap
执行以下命令,会在当前目录下生成npm-shrinkwrap.json文件,该文件记录了项目的详细依赖信息(如实反映,版本号固定)。
npm shrinkwrap
当项目中存在npm-shrinkwrap.json文件时,执行npm install会根据该文件信息去安装依赖包,因此每次安装的依赖都会完全相同,因此可以使用该命令来确保项目依赖的一致性。
注意该命令执行后,若后面有新增或修改或删除依赖,依赖信息不会自动更新到该文件,要再次执行npm shrinkwrap命令。
借助NPM5+的package-lock.json文件
在npm 5版本后,每次执行npm install xxxx会额外在执行一个动作,将项目的依赖信息跟新到package-lock.json文件。这是一个自动过程,每次新增或修改或删除依赖都会将项目依赖同步反应到改文件。
当项目中存在package-lock.json文件时,执行npm install会根据该文件信息去安装依赖包,因此每次安装的依赖都会完全相同,因此可以使用该命令来确保项目依赖的一致性。
当项目中存在package-lock.json文件时执行npm shrinkwrap会根据package-lock.json文件创建npm-shrinkwrap.json文件同时删除package-lock.json文件。执行npm install命令时,npm-shrinkwrap.json文件优先级会高于package-lock.json。
使用npm ci安装
条件:项目中必须有一个package-lock.json或npm-shrinkwrap.js
npm ci与npm i主要有以下的区别。
- npm i依赖package.json,而npm ci依赖package-lock.json。
- 当package-lock.json中的依赖于package.json不一致时,npm ci退出但不会修改package-lock.json。
- npm ci只可以一次性的安装整个项目依赖,但无法添加单个依赖项。
- npm ci安装包之前,会删除掉node_modules文件夹,因此他不需要去校验已下载文件版本与控制版本的关系,也不用校验是否存在最新版本的库,所以下载的速度更快。
- npm ci安装时,不会修改package.json与package-lock.json。