Changeset 版本管理原理

Changeset 是一个用于管理 monorepo 中多个包版本的工具,帮助团队跟踪变更、自动版本管理和生成 CHANGELOG。

什么是 Changeset?

Changeset 是一个用于管理 monorepo 中多个包版本的工具,由 Atlassian 开发。它帮助团队:

  • 跟踪变更:记录每个包的变化
  • 自动版本管理:根据变更类型自动更新版本号
  • 生成 CHANGELOG:自动生成变更日志
  • 发布管理:统一管理包的发布流程

为什么需要 Changeset?

传统版本管理的问题

在 monorepo 中,有多个包(如 @enterprise-ui/core@enterprise-ui/react19),传统方式的问题:

// ❌ 问题 1:手动管理版本号,容易出错
// packages/core/package.json
"version": "1.0.0"  // 需要手动更新

// packages/components-react19/package.json  
"version": "1.0.0"  // 需要手动更新

// ❌ 问题 2:不知道哪些包需要发布
// 修改了 core,但忘记更新版本号

// ❌ 问题 3:CHANGELOG 需要手动维护
// 容易遗漏或格式不一致

// ❌ 问题 4:依赖关系复杂
// core 更新了,react19 依赖它,需要同时更新

Changeset 的解决方案

// ✅ 1. 记录变更意图
pnpm changeset
// 选择包、变更类型、描述

// ✅ 2. 自动计算版本号
pnpm version
// 根据 changeset 自动更新版本

// ✅ 3. 自动生成 CHANGELOG
// 基于 changeset 文件自动生成

// ✅ 4. 统一发布
pnpm release
// 构建、版本更新、发布一步完成

Changeset 工作原理

1. 变更记录阶段

当你修改了代码,需要发布新版本时:

# 运行命令
pnpm changeset

# 交互式提示:
🦋  Which packages would you like to include?
❯ ◯ @enterprise-ui/core
  ◯ @enterprise-ui/react19
  ◯ docs (ignored)

🦋  What kind of change is this for @enterprise-ui/react19?
❯ patch  (修复 bug,向后兼容)
  minor  (新功能,向后兼容)
  major  (破坏性变更)

🦋  Please enter a summary for this change:
> 修复 Button 组件在 SSR 环境下的样式问题

生成的文件:

会在 .changeset/ 目录下生成一个 markdown 文件(随机文件名):

.changeset/xxxxx.md

---
"@enterprise-ui/react19": patch
---

修复 Button 组件在 SSR 环境下的样式问题

2. 版本更新阶段

准备发布时,运行:

pnpm version

Changeset 会执行以下操作:

  1. 读取所有 changeset 文件:扫描 .changeset/ 目录
  2. 计算新版本号
    • patch: 1.0.01.0.1
    • minor: 1.0.01.1.0
    • major: 1.0.02.0.0
  3. 更新 package.json:自动更新版本号
  4. 更新依赖版本:如果 react19 依赖 core,会自动更新依赖版本
  5. 生成 CHANGELOG.md:基于 changeset 文件生成变更日志
  6. 删除已使用的 changeset 文件:清理已处理的 changeset

3. 发布阶段

pnpm release

执行流程:

  1. 构建所有包:pnpm build
  2. 发布到 npm:changeset publish
  3. 创建 git tag:自动创建版本标签
  4. 推送到远程仓库:git push --tags

核心原理详解

1. Changeset 文件格式

Changeset 文件使用 YAML 前置元数据 + Markdown 内容:

---
"@enterprise-ui/react19": patch
"@enterprise-ui/core": minor
---

react19: 修复 Button 组件点击事件
core: 新增 debounce 工具函数

格式说明:

  • ---:YAML 前置元数据分隔符
  • "包名": 变更类型:指定包和变更类型(patch/minor/major)
  • 空行后的内容:变更描述(会出现在 CHANGELOG 中)

2. 版本号计算算法

Changeset 遵循 语义化版本(Semantic Versioning)

MAJOR.MINOR.PATCH

1.0.0
│ │ │
│ │ └─ patch: 修复 bug,向后兼容
│ └─── minor: 新功能,向后兼容
└───── major: 破坏性变更

版本更新规则:

  • 如果当前版本是 1.0.0,选择 patch1.0.1
  • 如果当前版本是 1.0.0,选择 minor1.1.0
  • 如果当前版本是 1.0.0,选择 major2.0.0

3. 依赖关系处理

Changeset 会自动处理包之间的依赖关系:

// 场景:core 更新到 1.1.0,react19 依赖 core

// packages/components-react19/package.json
{
  "dependencies": {
    "@enterprise-ui/core": "^1.0.0"  // 旧版本
  }
}

// 运行 pnpm version 后
{
  "dependencies": {
    "@enterprise-ui/core": "^1.1.0"  // 自动更新
  }
}

更新策略:

.changeset/config.json 中配置:

{
  "updateInternalDependencies": "patch"
  // 选项:
  // - "patch": 只更新 patch 版本
  // - "minor": 更新 minor 和 patch 版本
  // - "major": 更新所有版本
}

4. CHANGELOG 生成机制

Changeset 会根据 changeset 文件自动生成 CHANGELOG:

# @enterprise-ui/react19

## 1.0.1

### Patch Changes

- 修复 Button 组件在 SSR 环境下的样式问题 ([#123](https://github.com/...))

## 1.0.0

### Major Changes

- 初始版本发布

CHANGELOG 格式:

  • Major Changes:破坏性变更
  • Minor Changes:新功能
  • Patch Changes:Bug 修复

配置说明

.changeset/config.json

{
  "$schema": "https://unpkg.com/@changesets/config@2.3.1/schema.json",
  "changelog": "@changesets/cli/changelog",  // CHANGELOG 生成器
  "commit": false,                            // 不自动提交
  "fixed": [],                                // 固定版本(一起发布)
  "linked": [],                               // 链接版本(版本号同步)
  "access": "restricted",                     // npm 发布权限
  "baseBranch": "main",                      // 基础分支
  "updateInternalDependencies": "patch",     // 内部依赖更新策略
  "ignore": ["docs"]                          // 忽略的包(不发布)
}

配置项详解

配置项说明示例
changelogCHANGELOG 生成方式"@changesets/cli/changelog"
commit是否自动提交false(手动提交)
fixed固定版本组[["@enterprise-ui/core", "@enterprise-ui/react19"]]
linked链接版本组[["@enterprise-ui/core", "@enterprise-ui/react19"]]
accessnpm 发布权限"restricted"(私有)或 "public"
baseBranch基础分支"main"
updateInternalDependencies内部依赖更新策略"patch"(补丁版本)
ignore忽略的包["docs"](文档不发布)

实际使用示例

场景 1:修复 Bug

# 1. 修复了 Button 组件的 bug
# 修改了 packages/components-react19/src/components/Button/Button.tsx

# 2. 创建 changeset
pnpm changeset

# 选择:
# - 包:@enterprise-ui/react19
# - 类型:patch
# - 描述:修复 Button 组件点击事件不触发的问题

# 3. 提交代码
git add .
git commit -m "fix: Button 组件点击事件修复"
git push

# 4. 准备发布(在 CI/CD 或本地)
pnpm version
# 版本:1.0.0 → 1.0.1

# 5. 发布
pnpm release
# 发布到 npm

场景 2:添加新功能

# 1. 添加了新的 VirtualList 组件
# 新增了 packages/components-react19/src/components/VirtualList/

# 2. 创建 changeset
pnpm changeset

# 选择:
# - 包:@enterprise-ui/react19
# - 类型:minor(新功能)
# - 描述:新增 VirtualList 组件,支持虚拟滚动

# 3. 提交代码
git add .
git commit -m "feat: 新增 VirtualList 组件"
git push

# 4. 准备发布
pnpm version
# 版本:1.0.0 → 1.1.0

# 5. 发布
pnpm release

场景 3:破坏性变更

# 1. 重构了 API,不兼容旧版本
# 修改了 Button 组件的 props

# 2. 创建 changeset
pnpm changeset

# 选择:
# - 包:@enterprise-ui/react19
# - 类型:major(破坏性变更)
# - 描述:重构 Button 组件 API,移除 deprecated props

# 3. 提交代码
git add .
git commit -m "BREAKING: 重构 Button 组件 API"
git push

# 4. 准备发布
pnpm version
# 版本:1.0.0 → 2.0.0

# 5. 发布
pnpm release

最佳实践

1. 每次 PR 都创建 changeset

# 修改代码后
git checkout -b fix/button-click

# 修改代码...

# 创建 changeset
pnpm changeset

# 提交 changeset 文件
git add .changeset/
git commit -m "fix: Button 组件点击事件修复"

2. 合并 PR 前检查 changeset

在 CI/CD 中检查:

# .github/workflows/ci.yml
- name: Check for changeset
  run: |
    if [ -z "$(git diff --name-only origin/main | grep '.changeset')" ]; then
      echo "❌ 没有 changeset 文件"
      exit 1
    fi

3. 发布前检查

# 1. 确保所有 changeset 都已合并
git pull

# 2. 运行版本更新
pnpm version

# 3. 检查生成的 CHANGELOG
cat packages/components-react19/CHANGELOG.md

# 4. 确认版本号正确
cat packages/components-react19/package.json | grep version

# 5. 发布
pnpm release

常见问题

Q1: 忘记创建 changeset 怎么办?

可以补创建 changeset:

# 方案 1:补创建 changeset
pnpm changeset

# 方案 2:手动创建文件
# .changeset/xxxxx.md
---
"@enterprise-ui/react19": patch
---

修复说明

Q2: 如何撤销 changeset?

# 删除 changeset 文件
rm .changeset/xxxxx.md

# 或者修改内容
# 编辑 .changeset/xxxxx.md

Q3: 如何跳过某个包的版本更新?

// .changeset/config.json
{
  "ignore": ["docs", "example"]
}

总结

Changeset 的核心价值:

  • 简化版本管理:自动计算版本号,减少人为错误
  • 跟踪变更:记录每个包的变化,便于追溯
  • 自动生成 CHANGELOG:节省时间,格式统一
  • 依赖管理:自动更新内部依赖版本
  • 发布流程:统一管理发布流程

核心思想:

Changeset 通过记录变更意图(changeset 文件),在发布时自动计算版本号、更新依赖、生成 CHANGELOG,实现了版本管理的自动化和规范化。