npm版本固化
在项目开发中,我们需要管理复杂的项目依赖。npm包版本的标准基于semver1,它为依赖的升级提供了便利,但也导致了安装依赖的不一致性。出于以下考虑,我们需要版本固化方案锁定依赖的版本:
- 保证不同环境,不同机器下依赖安装的一致性,
- 避免某些依赖的更新引入新的bug。
目前的版本固化方案有npm shrinkwrap,yarn以及npm package-lock。
npm shrinkwrap
版本固化
通过执行命令npm shrinkwrap
,可以根据node_modules
目录下的依赖生成名为npm-shrinkwrap.json
的文件。这个文件描述了安装依赖所需要的基本信息,之后执行npm install
就可根据这个文件生成同样的node_modules
目录。
以npm@4.2.0
为例:
{
"name": "test",
"version": "1.0.0",
...
"dependencies": {
"path-to-regexp": "^1.7.0"
},
"devDependencies": {},
...
}
以上的package.json
会生成如下的npm-shrinkwrap.json
:
{
"name": "test",
"version": "1.0.0",
"dependencies": {
"isarray": {
"version": "0.0.1",
"from": "isarray@0.0.1",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz"
},
"path-to-regexp": {
"version": "1.7.0",
"from": "path-to-regexp@>=1.7.0 <2.0.0",
"resolved": "https://registry.npmjs.org/-/path-to-regexp-1.7.0.tgz"
}
}
}
当重新安装依赖时,npm install
会安装path-to-regexp@1.7.0
及其依赖isarray@0.01
。
值得一提的是npm-shrinkwrap.json
中的dependencies
和node_modules
下的依赖均为嵌套结构。如有需要可以执行npm dedupe
来去除重复的包,使依赖树尽量扁平化。
更新依赖
可以使用npm update
更新相应依赖,随后需要手动重新生成npm-shrinkwrap.json
。
也可以执行npm install <name>@<version> --save
安装指定版本依赖,该指令会自动更新npm-shrinkwrap.json
。
yarn
当使用yarn安装依赖时,会自动生成yarn.lock
,这个文件保存了每个依赖的版本号以及checksum。
同样以上一节的package.json
为例,生成的yarn.lock
如下:
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
isarray@0.0.1:
version "0.0.1"
resolved "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf"
path-to-regexp@^1.7.0:
version "1.7.0"
resolved "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.7.0.tgz#59fde0f435badacba103a84e9d3bc64e96b9937d"
dependencies:
isarray "0.0.1"
出于团队协作的考虑,yarn.lock
中的依赖只有一层,这样可以方便开发者比较差异,解决冲突。但这种扁平化的格式导致仅凭yarn.lock
并能得知项目的直接依赖,依赖的嵌套关系需要从package.json
推断,因此yarn能够固化依赖的版本,却不能完全还原node_modules
中依赖的位置。2
更新依赖
当执行yarn add/upgrade/remove
时,yarn.lock
会自动更新。也可在package.json
中增加resolutions
字段手动指定某个包的依赖。3
npm package-lock
如果使用npm v5安装依赖,会自动生成package-lock.json
,其实现同npm-shrinkwrap.json
相同。之所以用新的文件,是为了便于理解,并能够向后兼容。4
npm v5中,增删了一些package-lock.json
文件中的字段,以npm@5.5.1
为例,上述例子生成的package-lock.json
如下:
{
"name": "test",
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"isarray": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
"integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
},
"path-to-regexp": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.7.0.tgz",
"integrity": "sha1-Wf3g9DW62suhA6hOnTvGTpa5k30=",
"requires": {
"isarray": "0.0.1"
}
}
}
}
关于package-lock.json
和npm-shrinkwrap.json
两个文件5,有几点需要注意:
- 发布npm包时,并不会带上
package-lock.json
- 安装或更新npm包时,优先级
npm-shrinkwrap.json
>package-lock.json
- 执行
npm shrinkwrap
时若存在package-lock.json
,会将其重命名为npm-shrinkwrap.json
并更新
更新依赖
同npm shrinkwrap。注意npm v5会默认 --save。
总结
对一个项目而言,package.json
定义了作者期望的依赖及其版本,而npm-shrinkwrap.json
、yarn.lock
或者package-lock.json
则可以视为某次安装后所有的依赖及其版本的快照。
当然,版本固化只是一个技术方案,实际工程中应该权衡后决定是否使用。67
依赖也分为不同的类型,对optionalDependencies,版本固化方案还存在一些问题。89