Skip to content

版本管理规范

本文档面向两类读者:

  • 组件库使用者:了解版本号的含义,判断升级风险
  • 组件库开发者:掌握版本号的制定规则,以及如何使用 Changeset 管理发布流程

什么是语义化版本

版本号并不是随意递增的数字,它应该向使用者传达一个明确的信号:这次更新会不会影响我现有的代码?

语义化版本(Semantic Versioning,简称 SemVer)就是为了解决这个问题而设计的。版本号格式为:

主版本号.次版本号.修订号

示例:2.4.1

每一段数字代表不同程度的变化:

版本段含义典型场景
主版本号(Major)不兼容的 API 修改删除或重命名了组件的 props、更改了组件的默认行为
次版本号(Minor)向下兼容的新功能新增了一个 prop、新增了一个组件
修订号(Patch)向下兼容的问题修正修复了样式 bug、修正了错误的 TypeScript 类型

使用者如何判断升级风险

当前版本:1.4.2

升级到 1.4.3  →  只有 bug 修复,可以放心升级
升级到 1.5.0  →  有新功能,升级后旧代码仍然正常工作
升级到 2.0.0  →  有破坏性变更,升级前需要阅读迁移指南

关于 0.x.x 版本

主版本号为 0 时(如 0.3.1),表示软件处于初始开发阶段,API 尚未稳定,任何更新都可能包含破坏性变更。从 1.0.0 起,版本号才严格遵循上表的规则。

开发者如何递增版本号

规则一:主版本号递增时,次版本号和修订号必须归零。

✅ 1.4.2  →  2.0.0   (主版本升级)
❌ 1.4.2  →  2.4.2   (次版本号应归零)

规则二:次版本号递增时,修订号必须归零。

✅ 1.4.2  →  1.5.0   (次版本升级)
❌ 1.4.2  →  1.5.2   (修订号应归零)

规则三:版本一旦发布,内容不可修改。

如果已发布的版本有问题,只能发布新版本修复,不能修改已发布版本的内容。


先行版本号

在新版本正式发布之前,通常需要经历测试阶段。这时可以发布先行版本(prerelease),让内部团队或早期用户提前验证。

先行版本号的格式是在修订号后面加上连接号和标识符:

1.0.0-alpha        # 内部早期测试,非常不稳定
1.0.0-alpha.1      # alpha 阶段第 1 次迭代
1.0.0-beta         # 功能基本完整,开放外部测试
1.0.0-beta.1
1.0.0-beta.2
1.0.0-rc.1         # Release Candidate,候选正式版
1.0.0              # 正式版

先行版本的优先级

先行版本的优先级低于对应的正式版本。完整的优先级排序(从低到高)如下:

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
为什么 beta.2 < beta.11?

标识符中只含数字时,按数值大小比较(11 > 2),因此 beta.11 优先级高于 beta.2。 这也是为什么版本号中的数字禁止在前方补零beta.02 这种写法是非法的,应写作 beta.2

使用者注意事项

先行版本表示该版本并非稳定版,可能无法满足预期的兼容性需求。在生产环境中,请确保使用正式版本。

安装先行版本需要显式指定版本号,npm install 不会自动安装先行版本:

bash
# 安装正式版(默认行为)
npm install @pt/common-ui

# 安装指定的 beta 版本
npm install @pt/common-ui@1.0.0-beta.2

# 查看所有已发布版本(含先行版本)
npm view @pt/common-ui versions --json

使用 Changeset 管理版本发布

以下内容面向组件库开发者。

本项目使用 Changeset 管理 monorepo 中各包的版本号与发布流程。

Changeset 的核心思路是:将"描述变更"和"发布版本"两件事分开

  • 开发阶段:每次提 PR 时附上一个变更描述文件(changeset)
  • 发布阶段:统一根据所有变更描述文件计算版本号、生成 CHANGELOG、发布 npm

日常开发流程

第一步:完成开发,创建变更集

bash
pnpm changeset

命令行会交互式引导你完成三件事:

  1. 选择受影响的包 — 用空格键多选,回车确认
  2. 选择变更类型major(破坏性变更)/ minor(新功能)/ patch(问题修复)
  3. 填写变更描述 — 一句话说明本次修改内容,会写入 CHANGELOG

完成后,.changeset/ 目录下会自动生成一个 Markdown 文件,例如:

md
---
"@pt/common-ui": minor
"@pt/react-common": patch
---

Button 组件新增 `loading` 状态;修复 Input 组件在 Safari 下的样式问题。

将这个文件和你的代码一起提交到 git。 它是后续自动计算版本号的依据。

一次开发可以有多个变更集

如果一个 PR 中涉及多个包的不同类型变更,可以多次执行 pnpm changeset 创建多个变更集文件,Changeset 会在发布时合并计算。

第二步:更新版本号

待所有 PR 合并到主分支后,执行:

bash
pnpm changeset version

Changeset 会自动:

  • 读取所有未处理的变更集文件
  • 计算每个包的新版本号
  • 更新对应包的 package.json
  • 生成或更新 CHANGELOG.md
  • 删除已处理的变更集文件

执行后检查 package.jsonCHANGELOG.md 的变化,确认无误后提交。

第三步:发布

根据目标 registry 选择对应命令:

bash
pnpm release:npm      # 发布到公共 npm registry
pnpm release:company  # 发布到公司内部 registry
pnpm release:personal # 发布到个人 registry

这些命令会在发布前自动切换对应的环境变量配置,无需手动修改 .npmrc


发布先行版本

当一个功能尚未稳定、希望提前让团队或用户测试时,可以发布 beta / alpha / rc 版本。

进入 pre 模式

bash
pnpm changeset pre enter beta
# 或者
pnpm changeset pre enter alpha
pnpm changeset pre enter rc

执行后,根目录会生成 .changeset/pre.json 文件:

json
{
  "mode": "pre",
  "tag": "beta",
  "initialVersions": {
    "@pt/common-ui": "0.9.0"
  },
  "changesets": []
}

必须提交 pre.json

.changeset/pre.json 记录了当前处于哪个 pre tag 以及各包的初始版本,必须提交到 git。多人协作时,Changeset 依赖此文件追踪 beta 版本号的递增,丢失该文件会导致版本号混乱。

正常创建变更集并发布

进入 pre 模式后,流程与日常开发完全相同:

bash
pnpm changeset         # 创建变更集
pnpm changeset version # 版本号自动变为 x.x.x-beta.1、x.x.x-beta.2 ...
pnpm release:npm       # 发布

每次执行 changeset version,beta 后缀数字会自动递增:

0.9.0  →  1.0.0-beta.1  →  1.0.0-beta.2  →  1.0.0-beta.3 ...

退出 pre 模式,发布正式版

测试完成、准备正式发布时:

bash
pnpm changeset pre exit
pnpm changeset version  # 版本号归为正式版,如 1.0.0
pnpm release:npm

常见问题

Q:我只改了一行注释或文档,需要创建变更集吗?

不需要。如果本次修改不涉及任何包对外发布的内容(如只改了 CI 配置、内部文档、测试文件),执行 pnpm changeset 时在包选择步骤直接回车跳过,不选任何包即可,Changeset 不会创建文件。


Q:多个包之间有依赖关系,升级一个包会影响其他包的版本吗?

会有部分联动,但不是全自动的。具体规则是:

  • 如果包 A 依赖包 B,当包 B 版本升级后,Changeset 会自动更新包 A 的 package.json 中对包 B 的依赖版本号
  • 但包 A 本身的版本号不会自动递增,除非你在变更集中明确标记了包 A

也就是说,只有你认为包 A 的用户需要感知这次联动时,才需要手动为包 A 创建变更集。


Q:changeset versionchangeset publish 为什么分开执行,不能一步完成吗?

分开执行是有意为之的,这样可以在发布前进行 code review。推荐的流程是:

  1. changeset version 只修改本地文件(package.json + CHANGELOG.md
  2. 提交这些文件,创建一个 "Release PR" 供团队审查
  3. PR 合并后,在 CI 中执行 changeset publish 推送到 npm

这样每一次发布都有完整的审查记录。


Q:已经发布了 1.0.0-beta.1,发现有 bug,应该怎么做?

直接修复 bug,然后走正常流程创建变更集并执行 changeset version,版本号会自动升为 1.0.0-beta.2。不要尝试修改已发布的 1.0.0-beta.1 的内容——根据语义化版本规范,已发布的版本内容不可修改


Q:使用者如何在 package.json 中锁定版本范围?

推荐根据实际需求选择合适的版本范围写法:

json
{
  "dependencies": {
    "@pt/common-ui": "^1.4.2"
  }
}
写法含义
"1.4.2"精确锁定,只安装这一个版本
"^1.4.2"允许次版本和修订号升级(>=1.4.2 <2.0.0
"~1.4.2"只允许修订号升级(>=1.4.2 <1.5.0

对于处于 0.x.x 阶段的包,^ 的行为有所不同——^0.4.2 等同于 ~0.4.2,只允许修订号升级,因为 0.x 阶段的次版本升级也可能包含破坏性变更。

Released under the MIT License.