版本管理规范
本文档面向两类读者:
- 组件库使用者:了解版本号的含义,判断升级风险
- 组件库开发者:掌握版本号的制定规则,以及如何使用 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 不会自动安装先行版本:
# 安装正式版(默认行为)
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
日常开发流程
第一步:完成开发,创建变更集
pnpm changeset命令行会交互式引导你完成三件事:
- 选择受影响的包 — 用空格键多选,回车确认
- 选择变更类型 —
major(破坏性变更)/minor(新功能)/patch(问题修复) - 填写变更描述 — 一句话说明本次修改内容,会写入 CHANGELOG
完成后,.changeset/ 目录下会自动生成一个 Markdown 文件,例如:
---
"@pt/common-ui": minor
"@pt/react-common": patch
---
Button 组件新增 `loading` 状态;修复 Input 组件在 Safari 下的样式问题。将这个文件和你的代码一起提交到 git。 它是后续自动计算版本号的依据。
一次开发可以有多个变更集
如果一个 PR 中涉及多个包的不同类型变更,可以多次执行 pnpm changeset 创建多个变更集文件,Changeset 会在发布时合并计算。
第二步:更新版本号
待所有 PR 合并到主分支后,执行:
pnpm changeset versionChangeset 会自动:
- 读取所有未处理的变更集文件
- 计算每个包的新版本号
- 更新对应包的
package.json - 生成或更新
CHANGELOG.md - 删除已处理的变更集文件
执行后检查 package.json 和 CHANGELOG.md 的变化,确认无误后提交。
第三步:发布
根据目标 registry 选择对应命令:
pnpm release:npm # 发布到公共 npm registry
pnpm release:company # 发布到公司内部 registry
pnpm release:personal # 发布到个人 registry这些命令会在发布前自动切换对应的环境变量配置,无需手动修改 .npmrc。
发布先行版本
当一个功能尚未稳定、希望提前让团队或用户测试时,可以发布 beta / alpha / rc 版本。
进入 pre 模式
pnpm changeset pre enter beta
# 或者
pnpm changeset pre enter alpha
pnpm changeset pre enter rc执行后,根目录会生成 .changeset/pre.json 文件:
{
"mode": "pre",
"tag": "beta",
"initialVersions": {
"@pt/common-ui": "0.9.0"
},
"changesets": []
}必须提交 pre.json
.changeset/pre.json 记录了当前处于哪个 pre tag 以及各包的初始版本,必须提交到 git。多人协作时,Changeset 依赖此文件追踪 beta 版本号的递增,丢失该文件会导致版本号混乱。
正常创建变更集并发布
进入 pre 模式后,流程与日常开发完全相同:
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 模式,发布正式版
测试完成、准备正式发布时:
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 version 和 changeset publish 为什么分开执行,不能一步完成吗?
分开执行是有意为之的,这样可以在发布前进行 code review。推荐的流程是:
changeset version只修改本地文件(package.json+CHANGELOG.md)- 提交这些文件,创建一个 "Release PR" 供团队审查
- 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 中锁定版本范围?
推荐根据实际需求选择合适的版本范围写法:
{
"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 阶段的次版本升级也可能包含破坏性变更。
