跳到正文

package.json 中波浪号~ 异或号^ 是什么意思?

后端3 min
目录(12)

执行 npm install lodash 时,package.json 里写入的往往不是精确版本 4.17.21,而是 ^4.17.21~4.17.21。这两个前缀决定 npm 在后续 npm update、安装传递依赖时,允许解析到哪个版本区间

要读懂它们,得先弄清版本号本身的语义,再看 npm 如何把前缀翻译成范围。

SemVer:版本号三段各代表什么

语义化版本(SemVer) 规定标准版本号为 主版本号.次版本号.修订号,即 X.Y.Z

段位英文名何时递增
XMajor(主版本)做了不兼容的 API 修改
YMinor(次版本)做了向下兼容的功能新增
ZPatch(修订)做了向下兼容的问题修正

几个容易混的点:

  • 1.2.3 才是严格的 SemVer;v1.2.3 里的 v 只是常见前缀,规范本身不要求它。
  • 0.y.z 处于初始开发阶段,API 不保证稳定1.0.0 才通常被视为公共 API 成型的分界。
  • 先行版本(如 1.2.3-beta.1)和构建元数据(如 1.2.3+20240101)可以接在后面,但日常依赖里见得少,本文不展开。

package.json 写的是「范围」,不是钉死一个版本

dependencies 里的值是版本范围(range),不是单个版本字符串。npm 安装时用 node-semver 判断某个已发布版本是否落在范围内。

下面两个符号是最常用的简写,分别叫 Tilde Range(波浪号)Caret Range(插入符,即 ^

波浪号 ~:尽量锁在小版本内

node-semver 对 ~ 的定义

如果写全了三段版本,只允许**修订号(patch)变化;如果只写了两段或一段,则允许次版本号(minor)**变化。

记法:~^ 更保守,变动空间更小。

主版本 ≥ 1

写法等价范围通俗理解
~1.2.3>=1.2.3 <1.3.0锁定 1.2.x,补丁可升
~1.2>=1.2.0 <1.3.0同上,省略修订号时补 0
~1>=1.0.0 <2.0.0锁定 1.x,次版本可升

~1.2.3 为例:

✅ 允许:1.2.3  1.2.4  1.2.99
❌ 拒绝:1.2.2  1.3.0  2.0.0

主版本为 0

0.x 阶段规则相同,只是数字小一号:

写法等价范围通俗理解
~0.2.3>=0.2.3 <0.3.0锁定 0.2.x
~0.2>=0.2.0 <0.3.0同上
~0>=0.0.0 <1.0.0锁定 0.x

插入符 ^:允许兼容范围内的次版本升级

node-semver 对 ^ 的定义

允许那些不改变从左到右第一个非零段位的更新。

换句话说:最左边那个非 0 的数字,就是「不能跨过去」的边界。

主版本 ≥ 1:次版本和修订号都能升

写法等价范围通俗理解
^1.2.3>=1.2.3 <2.0.01.x 内任意兼容版本
^1.2>=1.2.0 <2.0.0同上
^1>=1.0.0 <2.0.0同上

^1.2.3 为例:

✅ 允许:1.2.3  1.3.0  1.9.9
❌ 拒绝:1.2.2  2.0.0

这也是 npm install默认行为save-prefix 默认为 ^):在 major 不变的前提下自动跟上新功能和补丁。

主版本为 0:边界随段位收缩

0.x 时,第一个非零段位不再是 major,规则会「缩紧」:

写法等价范围锁定的段位
^0.2.3>=0.2.3 <0.3.0次版本 0.2(等同 ~0.2.3
^0.0.3>=0.0.3 <0.0.4修订号 0.0.3(只允许补丁)
^0.1.2>=0.1.2 <0.2.0次版本 0.1

最常见的误区

很多人以为 ^0.1.2 表示 >=0.1.2 <1.0.0,实际上它是 >=0.1.2 <0.2.0

原因在于 SemVer 把 0.y.z 视为不稳定期,node-semver 也据此假定:0.2.x0.3.0 之间可能存在破坏性变更,因此 ^ 不会帮你跨过 0.2

^0.1.2

✅ 允许:0.1.2  0.1.9
❌ 拒绝:0.1.1  0.2.0  1.0.0   ← 0.2.0 和 1.0.0 都会被拒绝

~^ 怎么选

场景建议原因
应用项目、日常库依赖^(npm 默认)自动获得兼容范围内的修复和新功能
对补丁升级也要严格控制~连次版本升级都不接受
必须可复现的构建精确版本 1.2.3 + lockfile范围只表达意图,真正锁定靠 package-lock.json / bun.lock
0.x 的库格外小心 ^范围可能比你想的窄;若作者频繁 breaking,考虑钉死版本

无论写 ^ 还是 ~lockfile 才是安装时的最终裁决者。版本前缀只影响「允许 npm 解析到多新的版本」,不改变「这次装的就是 lockfile 里那一版」的事实。

速查对照

把上面的规则收成一张表,遇到不熟悉的写法可以直接查:

前缀示例等价范围允许升级到什么
~~1.2.3>=1.2.3 <1.3.01.2.x 补丁
~~1>=1.0.0 <2.0.0整个 1.x
^^1.2.3>=1.2.3 <2.0.0整个 1.x
^^0.2.3>=0.2.3 <0.3.00.2.x
^^0.0.3>=0.0.3 <0.0.40.0.3 的补丁

不确定某个版本是否命中范围时,可以用 node-semver 的 CLI 验证:

npx semver -r "^1.2.3" 1.2.2 1.2.3 1.9.0 2.0.0
# 输出:1.2.3  1.9.0

相关文档

分享到