Changesets 工作流:Monorepo 项目中的版本管理与发包自动化
大家好,欢迎来到今天的讲座。今天我们来深入探讨一个在现代前端工程化中越来越重要的主题——Changesets 工作流,特别是在 Monorepo(多包仓库)项目中如何实现高效的版本管理和自动化发布流程。
如果你正在维护一个包含多个独立模块的 Monorepo(比如使用 Lerna、Nx 或 Yarn Workspaces),那你一定遇到过这些问题:
- 每次改了一个包,都要手动判断是否需要发版?
- 版本号混乱?比如
v1.0.0和v1.0.1实际上只改了文档? - 发布时依赖关系没处理好,导致生产环境出错?
- 团队成员不统一语义化版本规范,导致版本混乱?
这些问题,在使用 Changesets 后可以得到系统性解决。
什么是 Changesets?
Changesets 是一个由 GitHub 开源团队开发的工具,用于帮助你管理多包项目的版本变更和发布流程。它通过一个简单的“变更描述文件”机制,让你在每次代码提交后明确说明:“我这次改了什么”,然后自动决定哪些包需要发版、版本号如何递增。
它的核心思想是:
先记录变更 → 再决定发布 → 最后自动化发包
这不仅提升了版本管理的透明度,还极大减少了人为错误。
为什么要在 Monorepo 中用 Changesets?
Monorepo 的优势在于共享代码、统一构建、方便协作。但代价是:
- 包之间相互依赖复杂
- 手动版本管理容易出错
- 发布流程繁琐
Changesets 提供了一种轻量级但强大的方式来应对这些挑战:
| 传统做法 | Changesets 做法 |
|---|---|
| 手动打 tag + npm publish | 自动识别变更并生成 changelog |
| 依赖关系靠人工维护 | 自动检测依赖链并排序发布顺序 |
| 版本号随意写 | 严格遵循语义化版本(SemVer)规则 |
| 发布失败难回滚 | 变更记录可追溯,支持一键回退 |
✅ 它不是替代你的 CI/CD 流水线,而是为它提供智能决策依据。
如何集成 Changesets 到你的 Monorepo?
我们以一个典型的 Yarn Workspaces + TypeScript 的 Monorepo 为例(结构如下):
my-monorepo/
├── packages/
│ ├── core/
│ │ └── package.json
│ ├── ui/
│ │ └── package.json
│ └── utils/
│ └── package.json
├── .changeset/
│ └── config.json
├── package.json
└── yarn.lock
第一步:安装 Changesets
yarn add -D @changesets/cli
或者用 npm:
npm install --save-dev @changesets/cli
第二步:初始化配置
运行以下命令创建初始配置:
npx changeset init
这会生成一个 .changeset/config.json 文件,内容如下:
{
"packages": ["packages/*"],
"access": "public",
"commit": false,
"sign": false
}
关键参数解释:
| 参数 | 说明 |
|---|---|
packages |
要监控的包路径(支持通配符) |
access |
发布权限(public / restricted) |
commit |
是否自动 commit 变更文件(通常设为 false) |
sign |
是否签名(用于企业级安全场景) |
第三步:编写变更记录(Change Entry)
每次你要发布新版本前,执行:
npx changeset add
你会看到交互式提示:
? What kind of change is this? (Use arrow keys)
❯ patch (bug fix or small improvement)
minor (adds functionality in a backwards-compatible way)
major (breaking change)
none (no release needed)
选择后,它会创建一个 .changeset/xxx.md 文件,例如:
---
"package": "core"
"type": "patch"
"release": true
---
Fixed typo in error message.
这个文件就是“变更描述”,后续会被用来决定版本号和生成 changelog。
✅ 这个过程强制你在代码提交后明确告诉系统:“这次改了什么,要不要发版”。
自动化发布流程设计(CI/CD 集成)
现在我们来看如何将 Changesets 整合进 CI 流程,实现真正的自动化发布。
假设你使用 GitHub Actions,以下是完整的 .github/workflows/release.yml 示例:
name: Release
on:
push:
branches: [ main ]
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '18'
registry-url: 'https://registry.npmjs.org/'
- name: Install dependencies
run: yarn install --frozen-lockfile
- name: Create release
run: npx changeset version
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Publish packages
run: npx changeset publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
这段脚本做了三件事:
changeset version:根据.changeset/*.md文件生成新的版本号,并更新每个包的package.json。changeset publish:自动发布所有标记为release: true的包到 npm。- 使用
NODE_AUTH_TOKEN确保认证安全。
🧠 小技巧:你可以加一个条件判断,只在主分支合并时触发发布,避免误操作。
实战案例:一个真实的 Monorepo 发布流程
假设我们的项目有三个包:
| 包名 | 当前版本 | 变更类型 |
|---|---|---|
| core | v1.2.0 | patch(修复 bug) |
| ui | v1.0.0 | minor(新增按钮组件) |
| utils | v0.5.0 | none(仅文档修改) |
当你运行 npx changeset add 并分别选择:
core: patchui: minorutils: none
最终生成的 .changeset/ 目录结构:
.changeset/
├── 2024-06-01--core.patch.md
├── 2024-06-01--ui.minor.md
└── 2024-06-01--utils.none.md
然后执行 npx changeset version,结果如下:
// packages/core/package.json
{
"version": "1.3.0"
}
// packages/ui/package.json
{
"version": "1.1.0"
}
// packages/utils/package.json
{
"version": "0.5.0" // 不变
}
接着 npx changeset publish 会按依赖顺序发布(比如 ui 依赖 core,则先发 core 再发 ui),避免依赖冲突。
高级特性:自定义版本策略 & Changelog 自动生成
Changesets 默认基于语义化版本(SemVer)进行版本递增,但它也支持插件扩展:
1. 自定义版本规则(如时间戳或内部版本号)
可以通过 @changesets/semver 插件定制版本号格式。例如:
{
"plugins": [
"@changesets/semver"
]
}
也可以配合自定义脚本处理版本逻辑,比如:
// .changeset/config.js
module.exports = {
packages: ['packages/*'],
plugins: [
['@changesets/semver', {
bump: (type, currentVersion) => {
if (type === 'major') return `${currentVersion.split('.')[0]}.0.0`;
return currentVersion; // 自定义逻辑
}
}]
]
};
2. 自动生成 Changelog(推荐)
Changesets 支持输出 Markdown 格式的 changelog,非常适合作为 release note 发布:
npx changeset generate
生成示例:
## [1.3.0](https://github.com/user/my-monorepo/compare/v1.2.0...v1.3.0) (2024-06-01)
### Patch
- Fixed typo in error message. ([core])
## [1.1.0](https://github.com/user/my-monorepo/compare/v1.0.0...v1.1.0) (2024-06-01)
### Minor
- Added new Button component. ([ui])
你可以把这个文件上传到 GitHub Releases 页面,或者集成到文档网站(如 Docusaurus、Next.js)中展示。
常见问题与最佳实践
| 问题 | 解决方案 |
|---|---|
| ❌ 多人同时提交,变更冲突怎么办? | 使用 Git 分支隔离,建议每功能分支对应一个 .changeset/*.md 文件 |
| ❌ 发布失败怎么办? | Changesets 会在失败时保留 .changeset 文件,下次继续尝试;也可用 --dry-run 测试 |
| ❌ 如何控制发布范围? | 在 .changeset/config.json 中设置 packages 字段过滤目标包 |
❌ 不想每次手动 add? |
结合 husky + lint-staged,在 git commit 前自动触发 changeset add(见下文) |
最佳实践总结:
✅ 每次提交都要有变更记录 —— 即使是文档修改也要写清楚,便于追踪历史
✅ 保持变更描述简洁清晰 —— 不要写“修了一下”这种模糊语句
✅ 定期清理未发布的变更文件 —— 如果长时间未发布,可能遗漏重要信息
✅ 结合 PR 标签自动分类 —— 比如带 changelog: patch 的 PR 自动归类为 patch 类型
✅ 建立团队共识 —— 明确谁负责写变更描述,避免责任不清
总结:Changesets 是 Monorepo 的“版本指挥官”
通过今天的学习,你应该已经理解:
- Changesets 是一套声明式、可追踪、自动化的版本管理方案;
- 它特别适合 Monorepo 场景,能显著降低发布风险;
- 从添加变更记录 → 自动版本升级 → 一键发布,形成闭环;
- 可灵活扩展,满足不同团队的发布需求。
这不是一个“高级技巧”,而是一个工程化必备能力。尤其是在微前端、组件库、SDK 等场景下,Changesets 已经成为主流实践。
最后送一句来自官方文档的话:
“Changesets makes it easy to manage your monorepo’s releases without needing to think about version numbers or dependency chains.”
—— Changesets 官方文档
希望你能把这套方法应用到自己的项目中,告别混乱的版本号,拥抱清晰、可控的发布流程!
如果你还有疑问,欢迎留言讨论 👇
祝你早日打造一个稳定、高效、可维护的 Monorepo!