NPM 版本控制小坑
我们在项目中引入 NPM 模块时,需要对依赖进行有效的版本控制,否则当某个依赖做了不向下兼容的升级,就会造成我们项目出错。同样,我们在开发 NPM 模块时,也需要做好版本控制,以免给其他开发者造成困扰。
NPM 版本号规范
NPM 上所有模块都遵循 semver 2.0 规则。
简单规则如下:
版本格式:主版本号.次版本号.修订号,版本号递增规则如下:
- 主版本号:当你做了不兼容的 API 修改,
- 次版本号:当你做了向下兼容的功能性新增,
- 修订号:当你做了向下兼容的问题修正。
先行版本号及版本编译信息可以加到“主版本号.次版本号.修订号”的后面,作为延伸。
对于预发版本,还可以使用连字符 - 加一连串以句点分隔的标识符来修饰。范例:1.0.0-alpha、1.0.0-alpha.1、1.0.0-0.3.7、1.0.0-x.7.z.92。
基于这样的规则,我们在项目中选择 NPM 模块时候就可以对依赖进行有效的版本控制。
"dependencies": {
"animationjs": "~0.1.5",
"core-js": "^2.4.0",
"httpurl": ">0.1.1",
"kountdown": "<=0.1.2",
"lazyimg": "0.1.2",
"lie": "3.0.4-beta",
"modals": "*"
}
除此之外,NPM 还拓展了 tags 功能来增强基于 semver 的版本控制。tags 允许开发者更有效地分发自己的模块。
npm install lodash@beta
选择合适的 NPM 模块版本
上面例子展示几种常用的版本范围选择风格,我们详细来了解一下:
~x.y.z: 匹配大于x.y.z的z的最新版^x.y.z: 匹配大于x.y.z的y.z的最新版- 当
x为0时,^x.y.z等价于~x.y.z,即只会安装z的最新版本; - 当
x和y为0时,^x.y.z等价于x.y.z,即只会安装x.y.z版本;
- 当
>x.y.z或<=x.y.z: 大于x.y.z的最大版本或与x.y.z最接近的版本x.y.z: 选择x.y.z*: 任意版本,一般是最后一次正式发布版本(包括非 latest tag),不是最大版本号版本
这是最基本的模块选择,对于使用连字符 - 描述的预发版本,必须具体指定具体的先行版本号才安装。
由于所有 tags 公用一个命名空间,因此,我们在安装 NPM 模块时,很可能安装到其他 tags 下的模块。
我们以一个测试项目 tyd 为例:
通过 npm info <package_name> 可以查看某个 npm 模块的 tag 信息和版本信息。
$ npm info tyd
{ name: 'tyd',
'dist-tags': { latest: '6.0.1-beta.4', beta: '5.0.7-beta', alpha: '5.1.1' },
versions:
[ '0.0.1-beta',
'0.0.1',
'0.0.2',
'0.0.3',
'0.0.4',
'0.0.5',
'0.1.0',
'0.1.1',
'0.2.1',
'1.0.1',
'1.1.1',
'1.1.2',
'1.1.3',
'1.2.0',
'1.2.2',
'1.2.4',
'1.3.0',
'2.1.1',
'3.1.0',
'4.0.1',
'4.0.2',
'4.2.2',
'4.3.1-beta'
'5.0.1-beta.0.1',
'5.0.1-beta.0.2',
'5.0.1-beta.1.0',
'5.0.1-beta.1.1',
'5.0.1-beta.1.3',
'5.0.1-beta.2.0',
'5.0.3-beta',
'5.0.3',
'5.0.5-beta.1',
'5.0.6',
'5.0.7-beta',
'5.0.8',
'5.0.9-beta.0.1',
'5.1.1',
'5.1.2-beta.1',
'6.0.1-beta.2',
'6.0.1-beta.3',
'6.0.1-beta.4',
'6.1.2-beta.0.1' ],
/* 其他信息省略 */
}
我们测试使用不同的版本范围选择风格(NPM 版本 3.9.3),实际安装的版本如下列表:
*: 5.1.1 (该版本 tag 为 alpha)~0.0.1: 0.0.5 (该版本 tag 为 beta)^0.0.1: 0.0.1~4.0.1: 4.0.2 (该版本 tag 为 beta)^4.0.1: 4.2.2^4.2.2: 4.2.2~5.0.1-beta.0.1: 5.0.8^5.0.1-beta.0.1: 5.1.1~6.0.1-beta.2: 6.0.1-beta.4^6.0.1-beta.2: 6.0.1-beta.4<=4.0.2: 4.0.2 (该版本 tag 为 beta)>6.0.1-beta.4: Error>6.0.1-beta.2: 6.0.1-beta.4
通过以上测试我们可以发现一些规律:
- NPM 默认不会匹配带有预发版本信息的版本号,例如上面例1、例5和例6;
- 不同的 tag 对于范围选择无影响,如例1、例4、例11;
- 当匹配范围的设置了一个预发版本号,正式版本仍然有最高优先级,只有当无法匹配到任何正式版本后才会匹配预发版本,如例7、例8、例9、例10;
- NPM 无法跨正式版本号匹配预发版本,如例12、例13。
发布 NPM 模块时的坑
很多时候我们会发布预发模块到 NPM。这时候,如果我们只为这个预发版本打了一个 beta tag,那么,当一个用户升级依赖时,很有可能升级到一个预发的版本而出错。如上例中1、2、4,用户设置了一个正式版本的范围,最终却安装到一个预发版本。
所以发布 NPM 模块时,最好严格遵循 semver 规范,如果是预发版本,请用连字符 - 加其他信息命名预发版本号,这样,NPM 会默认匹配正式版本,反正用户使用了不稳定的模块。
那么,NPM tags 有什么用?
额,我也没有想明白。。
