跳到主要内容

语义化版本(SemVer)

语义化版本(Semantic Versioning,简称 SemVer)是一套版本号命名规范,旨在解决软件版本管理的混乱问题。它定义了一套清晰的规则,让开发者能够通过版本号了解软件的变化程度。

为什么需要语义化版本?

在软件开发中,依赖管理是一个复杂的问题。假设你的项目依赖三个库:A、B 和 C。A 依赖 D v1.0,B 依赖 D v1.5,而 C 依赖 D v2.0。这三个版本的 D 可能存在不兼容的 API 变更,如何选择正确的版本?

语义化版本通过明确的规则解决了这个问题:

  1. 版本号传达了变更的含义
  2. 版本号定义了兼容性的边界
  3. 版本号让依赖解析变得可预测

版本号格式

语义化版本号由三部分组成:主版本号.次版本号.修订号(MAJOR.MINOR.PATCH)

2.1.3
│ │ │
│ │ └── 修订号(Patch)
│ └──── 次版本号(Minor)
└────── 主版本号(Major)

版本号递增规则

主版本号(MAJOR)

当你做了不兼容的 API 变更时递增。这意味着升级主版本可能需要修改代码。例如:

  • 移除或重命名公共 API
  • 改变函数签名
  • 改变默认行为
  • 重大架构调整

次版本号(MINOR)

当你做了向后兼容的功能新增时递增。升级次版本通常是安全的。例如:

  • 新增公共 API
  • 新增可选参数
  • 性能优化
  • 新增配置选项

修订号(PATCH)

当你做了向后兼容的问题修复时递增。升级修订号应该是完全安全的。例如:

  • Bug 修复
  • 文档更新
  • 代码重构(不影响行为)

版本号递增示例

1.0.0 -> 1.0.1  修复 Bug,递增修订号
1.0.1 -> 1.1.0 新增功能,递增次版本号
1.1.0 -> 2.0.0 破坏性变更,递增主版本号

版本号从 0 开始

版本号 0.x.x 表示初始开发阶段,API 尚不稳定。在这个阶段,任何变更都是允许的,即使是破坏性变更。

0.1.0 -> 0.2.0  可能包含破坏性变更

当 API 稳定后,发布 1.0.0 版本,之后遵循语义化版本规则。

预发布版本

预发布版本用于在正式发布前进行测试。格式为 主版本.次版本.修订号-标识符.数字

预发布标识符

标识符含义示例
alpha内部测试版本1.0.0-alpha.1
beta公开测试版本1.0.0-beta.2
rc候选发布版本1.0.0-rc.1

预发布版本优先级

预发布版本的优先级低于对应的正式版本:

1.0.0-alpha.1 < 1.0.0-alpha.2 < 1.0.0-beta.1 < 1.0.0-rc.1 < 1.0.0

安装预发布版本

# 安装预发布版本
npm install package@beta
npm install [email protected]

# 安装 next 标签的版本
npm install package@next

版本范围语法

包管理工具使用版本范围语法来指定可接受的版本范围。

基本范围

语法含义匹配版本
1.2.3精确版本1.2.3
>1.2.3大于1.2.4 及以上
>=1.2.3大于等于1.2.3 及以上
<1.2.3小于1.2.2 及以下
<=1.2.3小于等于1.2.3 及以下

脱字符范围(^)

脱字符(^)允许不改变最左边非零数字的更新。这是 npm 默认使用的范围。

^1.2.3 := >=1.2.3 <2.0.0
^0.2.3 := >=0.2.3 <0.3.0
^0.0.3 := >=0.0.3 <0.0.4

理解规则

  • ^1.2.3:主版本号为 1,允许次版本和修订号更新
  • ^0.2.3:主版本号为 0,次版本号为 2,只允许修订号更新
  • ^0.0.3:主版本号和次版本号都为 0,相当于精确版本

实际应用

{
"dependencies": {
"express": "^4.18.2"
}
}

这意味着可以安装 4.18.24.x.x 的任何版本,但不会自动升级到 5.0.0

波浪号范围(~)

波浪号(~)只允许修订号更新。

~1.2.3 := >=1.2.3 <1.3.0
~1.2 := >=1.2.0 <1.3.0
~1 := >=1.0.0 <2.0.0

实际应用

{
"dependencies": {
"express": "~4.18.2"
}
}

这意味着可以安装 4.18.24.18.x 的任何版本,但不会升级到 4.19.0

^ 和 ~ 的区别

范围允许更新不允许更新
^1.2.31.2.4, 1.3.0, 1.4.02.0.0
~1.2.31.2.4, 1.2.51.3.0, 2.0.0

选择建议:

  • 使用 ^:信任库的维护者,希望获得新功能和修复
  • 使用 ~:更保守,只接受 Bug 修复
  • 使用精确版本:生产环境关键依赖,需要完全控制

范围组合

连字符范围

1.2.3 - 2.3.4 := >=1.2.3 <=2.3.4

或(||)

^1.0.0 || ^2.0.0

匹配 1.x.x2.x.x 的版本。

与(空格)

>=1.2.3 <1.3.0

同时满足两个条件。

通配符

* := 任意版本
1.x := >=1.0.0 <2.0.0
1.2.x := >=1.2.0 <1.3.0

版本比较规则

版本号按照以下规则比较:

  1. 从左到右依次比较主版本号、次版本号、修订号
  2. 数字比较,不是字符串比较
  3. 预发布版本优先级低于正式版本
1.0.0 < 2.0.0 < 2.1.0 < 2.1.1
1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-beta < 1.0.0

预发布版本比较

预发布标识符按点分隔,依次比较:

  • 纯数字:按数值比较
  • 非纯数字:按 ASCII 字典序比较
  • 数字标识符小于非数字标识符
1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-alpha.beta < 1.0.0-beta < 1.0.0-beta.2 < 1.0.0-beta.11 < 1.0.0-rc.1 < 1.0.0

版本管理实践

发布流程

首次发布

# 初始化版本
npm version 1.0.0

# 发布
npm publish

Bug 修复

# 修复 Bug 后
npm version patch # 1.0.0 -> 1.0.1

# 发布
npm publish

新增功能

# 新增功能后
npm version minor # 1.0.0 -> 1.1.0

# 发布
npm publish

破坏性变更

# 破坏性变更后
npm version major # 1.0.0 -> 2.0.0

# 发布
npm publish

预发布流程

# 创建 alpha 版本
npm version prerelease --preid=alpha # 1.0.0 -> 1.0.1-alpha.0

# 发布到 alpha 标签
npm publish --tag alpha

# 测试完成后,发布正式版本
npm version patch # 1.0.1-alpha.0 -> 1.0.1
npm publish

版本标签管理

# 查看标签
npm dist-tag ls my-package

# 添加标签
npm dist-tag add [email protected] stable

# 删除标签
npm dist-tag rm my-package old

# 安装特定标签版本
npm install my-package@beta

常用标签:

  • latest:最新稳定版本(默认)
  • next:下一个主版本
  • beta:测试版本
  • alpha:内部测试版本
  • canary:每日构建版本

依赖更新策略

开发环境

使用宽松的版本范围,获取最新功能和修复:

{
"dependencies": {
"express": "^4.18.2"
}
}

定期更新依赖:

# 检查过期依赖
npm outdated

# 更新到 package.json 允许的范围内
npm update

# 更新到最新版本
npx npm-check-updates -u
npm install

生产环境

使用精确版本或锁文件:

# 使用锁文件安装
npm ci

# 或使用精确版本
npm install --save-exact express

CI/CD 环境

始终使用锁文件:

npm ci

常见问题

1. 版本冲突

当两个依赖要求同一个包的不同版本时:

{
"dependencies": {
"package-a": "1.0.0",
"package-b": "2.0.0"
}
}

解决方案:

  • 使用 overrides(npm)或 resolutions(yarn)强制版本
  • 升级依赖以兼容同一版本
  • 寻找替代包

2. 主版本锁定

某些包的主版本之间差异很大:

{
"dependencies": {
"react": "^17.0.0",
"react-dom": "^17.0.0"
}
}

升级主版本前,务必阅读迁移指南。

3. 0.x 版本的不稳定性

0.x.x 版本可能随时发生破坏性变更:

{
"dependencies": {
"new-package": "^0.5.0"
}
}

建议使用精确版本:

{
"dependencies": {
"new-package": "0.5.0"
}
}

4. 预发布版本的意外安装

默认情况下,npm install package 不会安装预发布版本。但如果 package.json 中指定了预发布版本范围:

{
"dependencies": {
"package": "^1.0.0-beta.0"
}
}

可能会安装预发布版本。建议使用精确版本或正式版本范围。

版本号速查表

操作命令版本变化
修订号更新npm version patch1.0.0 → 1.0.1
次版本更新npm version minor1.0.0 → 1.1.0
主版本更新npm version major1.0.0 → 2.0.0
预发布版本npm version prerelease1.0.0 → 1.0.1-0
带标识预发布npm version prerelease --preid=beta1.0.0 → 1.0.1-beta.0
指定版本npm version 2.1.0→ 2.1.0

版本范围速查表

范围含义匹配示例
1.2.3精确版本仅 1.2.3
^1.2.3兼容版本1.2.3, 1.2.4, 1.3.0
~1.2.3近似版本1.2.3, 1.2.4
>1.2.3大于1.2.4 及以上
>=1.2.3大于等于1.2.3 及以上
<1.2.3小于1.2.2 及以下
<=1.2.3小于等于1.2.3 及以下
1.2.3 - 2.3.4范围1.2.3 到 2.3.4
^1.0.0 || ^2.0.01.x 或 2.x
*任意版本所有版本
1.x通配符1.0.0 到 1.x.x

了解更多