本文作者:IMWeb helinjiang 原文出处:IMWeb社区 未经同意,禁止转载
本文详细讨论了 npm 中依赖版本的版本号配置写法及比较。
1. 开篇
为了更好的进行说明,我们选择了 lodash 来演示,因为它是被其他模块依赖最多的模块之一。本文是在 windows 7 64位系统中进行测试,npm 版本为 v3.8.1
,其他的平台和 npm 版本在某些提示上可能会稍有不同。
运行 npm install lodash --save
命令,安装下载 loadash,此时 package.json
文件中会是这个样子的:
{
"name": "test",
"dependencies": {
"lodash": "^4.11.1"
}
}
有没注意到那个 ^4.11.1
? 4.11.1
是版本号很容易理解(这里只是当前的最新版本,后续 loadash 版本更新之后可能会有变化),前面的 ^
符号是什么鬼?你甚至还见过这样的 ~4.11.1
、 4.11.1
、<4.11.1
等写法,都有什么区别?
2. 语义化的版本控制
在进入主题之前,我们得先了解一个很重要的概念,就是语义化的版本控制(Semantic Versioning Specification (SemVer)),目前的版本为 v2.0.0
。具体规则请看官网文档,这里只是简单介绍。
语义化版本格式为:主版本号.次版本号.修订号
,例如 4.11.1
,版本号递增规则如下:
- 主版本号:当你做了不兼容的 API 修改,
- 次版本号:当你做了向下兼容的功能性新增,
- 修订号:当你做了向下兼容的问题修正。
我们先假设所有的 npm 包的版本命名都符合这个规范,这是讨论的基础。
3. 版本号的配置写法
在 package.json
文件中,我们配置 dependencies
等依赖关系时,有几种配置方式。
3.1 ^
(caret,插入符)和 ~
(tilde,波浪符)
^
(caret,插入符)和 ~
(tilde,波浪符)是我们见得最多的,也是最容易迷惑的,我们放在一起来对比,就会更明白些。除了在 package.json 中直接指定之外,我们也可以运行 npm install lodash@^3.3.0
或 npm install lodash@~3.3.0
来直接安装。
3.1.1 含义和对比
用法举例 | 含义 | 范围 | 备注 |
---|---|---|---|
^4.11.1 | Compatible with 4.11.1 | 4.11.1 <= version < 5.0.0(4.x.x 且 >=4.11.1) | 主版本号不变 |
~4.11.1 | Reasonably close to 4.11.1 | 4.11.1 <= version < 4.12.0(4.11.x 且 >=4.11.1) | 主版本号和次版本号都不变 |
很难用准确的词去翻译它们的含义,自己去查字典吧。
从其定义来看,使用 ^
会更激进,因为它会获得“尽可能新的且能够保持兼容性的版本”;而使用 ~
会更温和更保险,因为它会获得“尽可能靠近指定版本的升级版本”。
当它们也有共同点:
- 当通过这两种方式获取的结果中,主版本号一定是不变的,因为主版本号意味这 API 不兼容。
- 可选版本的最低版本号都是大于或等于指定的版本,不能比它还低;如果在该范围内没有任何版本,则会报错如下。
3.1.2 例外场景 0.x.x
任何规则都有例外。0.x.x
版本意味着“Anything can change at any time.”。主版本号为 0
是为了做快速开发。在版本成型之前,开发者可以任意更改其代码,甚至做不兼容的变更而不受约束,然后通过修改次要版本,来控制版本;如果你的软件被用于正式环境,或已经有了稳定的 API 被使用者依赖,则将其升级到 1.0.0
版本或以上。
因此,针对 0.x.x
,指定其依赖版本号时会更趋于谨慎,而 ^
的行为也变得和 ~
一样了。例如 ^0.3.0
和 ~0.3.0
取值都是 0.3.0 <= version < 0.4.0
3.1.3 自测一下
我们以 lodash 为例,这里有几份测试用例,如果你都能算对,那么说明你明白了其中的区别了。为了便于讨论,我们先列出 lodash 的所有有效版本,运行命令 npm view lodash versions
,获得结果如下:
[ '0.1.0', '0.2.0', '0.2.1', '0.2.2', '0.3.0', '0.3.1', '0.3.2', '0.4.0', '0.4.1', '0.4.2', '0.5.0-rc.1', '0.5.0', '0.5.1', '0.5.2', '0.6.0', '0.6.1', '0.7.0', '0.8.0', '0.8.1', '0.8.2', '0.9.0', '0.9.1', '0.9.2', '0.10.0', '1.0.0-rc.1', '1.0.0-rc.2', '1.0.0-rc.3', '1.0.0', '1.0.1', '1.0.2', '1.1.0', '1.1.1', '1.2.0', '1.2.1', '1.3.0', '1.3.1', '2.0.0', '2.1.0', '2.2.0', '2.2.1', '2.3.0', '2.4.0', '2.4.1', '2.4.2', '3.0.0', '3.0.1', '3.1.0', '3.2.0', '3.3.0', '3.3.1', '3.4.0', '3.5.0', '3.6.0', '3.7.0', '3.8.0', '3.9.0', '3.9.1', '3.9.2', '3.9.3', '3.10.0', '3.10.1', '4.0.0', '4.0.1', '4.1.0', '4.2.0', '4.2.1', '4.3.0', '4.4.0', '4.5.0', '4.5.1', '4.6.0', '4.6.1', '4.7.0', '4.8.0', '4.8.1', '4.8.2', '4.9.0', '4.10.0', '4.11.0', '4.11.1' ]
测试用例 | 返回结果 |
---|---|
^4.11.2 | error |
~4.11.2 | error |
^4.8.1 | 4.11.1 |
~4.8.1 | 4.8.2 |
^3.9.1 | 3.10.1 |
~3.9.1 | 3.9.3 |
^3.8.3 | 3.10.1 |
~3.8.3 | error |
^0.3.0 | 0.3.2 |
~0.3.0 | 0.3.2 |
3.1.4 "npm install xx --save" 不再使用 ~
npm 版本 在 v1.4.3
做了一次更新 (Node v0.10.26(Stable)开始将 npm 升级到 v1.4.3
), npm install xx --save
之后,保存在 package.json
文件中的依赖版本号前面,将使用 ^
(caret,插入符),而不是 ~
(tilde,波浪符)。
Default
npm install --save
and its counterparts to use the^
version specifier, instead of~
. (0a3151c,@mikolalysenko)
3.2 大于或小于指定版本
使用大于号(>
)或小于号(<
)的场景会比较少见,但 npm 也是支持的,
用法举例 | 含义 | 范围 |
---|---|---|
| 大于 4.11.1 的最新版本 | version > 4.11.1 |
<4.11.1 | 小于 4.11.1 的最新版本 | version < 4.11.1 |
测试用例 | 返回结果 |
---|---|
| 4.11.1 |
<3.8.1 | 3.8.0 |
3.3 等于指定版本
可以使用等号(=
),也可以不写。即 "lodash":"=3.8.0"
和 "lodash":"3.8.0"
是一样的意思。我们也可以通过 npm install lodash@3.8.0
来安装指定版本。
更多阅读
- Difference between tilde(~) and caret(^) in package.json
- "npm install --save" No Longer Using Tildes