一、@changesets/cli 是什么
一句话 :它是一个专门为 Monorepo(多包仓库) 设计的版本管理与发布工具。
它的核心工作流程是:
开发者写代码 → 声明"我要发布什么包、升什么级别" → 生成一个 .md 计划文件
↓
所有 PR 合并后,统一消费这些计划文件
↓
自动改版本号、写 CHANGELOG、发布到 npm
它本质上解决了 Monorepo 场景下的两个核心痛点:
| 痛点 | Changesets 的解法 |
|---|---|
| 多人同时改同一个包,版本号在 Git 中冲突 | 不直接改版本号,而是生成独立的 .md 计划文件,文件名随机,永远不会冲突 |
| 包之间有依赖,升级一个包需要同步更新依赖它的包 | updateInternalDependencies 配置,自动级联更新 |
在当前工程中,它作为 devDependencies 安装在根目录:
bash
// 根 package.json
"devDependencies": {
"@changesets/cli": "^2.31.1"
}
bash
"scripts": {
"changeset": "changeset", // → pnpm changeset
"version:pkgs": "changeset version", // → pnpm version:pkgs
"publish:pkgs": "changeset publish" // → pnpm publish:pkgs
}
二、哪些情况下需要使用
✅ 必须使用的情况
bash
你同时满足以下 3 个条件 → 必须用版本管理工具(Changesets 是首选之一):
✅ 多个 npm 包在同一个仓库里(Monorepo)
✅ 包之间有相互依赖关系
✅ 需要发布到 npm 仓库(公共或私有)
❌ 不需要的情况
| 场景 | 为什么不需要 |
|---|---|
| 单包仓库 | 直接改 package.json 版本号 + npm publish 就够,不需要 Changesets 的复杂度 |
| 应用项目(非库) | 应用不需要发布到 npm,只需要部署到服务器 |
| 不发布到 npm | 如果只是内部使用 workspace:* 协议引用,不需要版本管理 |
| 个人项目、单人维护 | 没有多人协作带来的版本号冲突问题 |
当前工程为什么需要
对照这个工程:
bash
✅ Monorepo:20+ 个包在 packages/ 下
✅ 相互依赖:business → composables → core,形成依赖链
✅ 发布到 npm:发布到阿里云私有仓库(packages.aliyun.com)
✅ 多人协作:团队开发
三、怎么使用
3.1 初始化(一次性)
bash
pnpm add -D @changesets/cli
pnpm changeset init
这会生成 .changeset/ 目录,包含 config.json 和 README.md。
当前工程的 config.json:
bash
{
"changelog": "@changesets/cli/changelog",
"commit": false,
"fixed": [],
"linked": [],
"access": "restricted",
"baseBranch": "master",
"updateInternalDependencies": "patch",
"ignore": ["test1", "test2", "example-page", "pc-demo", "pc-template", "@bht-next/docs"]
}
3.2 逐一解释每一个配置项:
bash
"$schema": "https://unpkg.com/@changesets/config@3.1.4/schema.json"
含义:JSON Schema 的声明,告诉编辑器(VS Code)这个 JSON 文件的结构规范,从而提供自动补全和字段校验。
实际效果:你在编辑 config.json 时,编辑器会提示哪些字段是合法的、值的类型是什么,写错了会标红。纯粹是开发体验优化,不影响运行时行为。
bash
"changelog": "@changesets/cli/changelog"
含义 :指定 CHANGELOG 的生成模板。值是一个 npm 包的路径,Changesets 会 require() 这个包来格式化 CHANGELOG。
默认值 :@changesets/cli/changelog(内置的默认模板)
实际效果 :执行 changeset version 时,生成的 CHANGELOG 是这样的格式:
bash
# @bht-next/business
2.0.0
Major Changes
该次提交日志
Patch Changes
本次提交日志
1.0.6
Patch Changes
分页参数修改
可以自定义 :如果你想要不同的 CHANGELOG 格式,可以指向自定义包,比如 @changesets/changelog-github(带 GitHub 链接的格式):
bash
"changelog": "@changesets/changelog-github"
bash
## 2.0.0
Major Changes
study (#123) ← 自动带 PR 链接
bash
"commit": false
含义 :changeset version 执行后,是否自动执行 git commit。
false (当前设置):只修改文件,不自动提交。你需要手动 git add + git commit。这是推荐做法,因为你可以检查版本变更是否正确后再提交。
true:自动提交。适合 CI/CD 全自动流程。
bash
"fixed": []
含义 :固定版本组 。数组中的包被强制绑定,它们的版本号永远保持一致。当其中任何一个包需要升级时,组内所有包一起升级到同一个版本号。
当前为空 :意味着这个工程中每个包独立管理自己的版本号,@bht-next/core 可以是 1.0.27,@bht-next/business 可以是 2.0.0,互不影响。
使用场景示例 :假设 @bht-next/business 和 @bht-next/ui 总是需要一起发布,版本号必须一致:
bash
"fixed": [["@bht-next/business", "@bht-next/ui"]]
效果:如果 business 需要从 2.0.0 升到 2.1.0,ui 就算没改代码,也会被迫 从 1.5.0 升到 2.1.0(取组内最高版本号)。
bash
"linked": []
含义 :关联版本组 。和 fixed 类似,但更宽松 ------组内包版本号不需要完全相同,只需在同一个 major 版本内即可。当组内某个包需要跨 major 升级时,其他包也一起升级 major。
当前为空:不做关联。
和 fixed 的区别:
fixed |
linked |
|
|---|---|---|
| 版本号一致性 | 必须完全相同 | 可以不同,但 major 版本同步 |
| 升级触发 | 任意包的任意级别变更都触发全组升级 | 只有 major 升级时触发全组 |
| 举例 | business@2.1.0, ui@2.1.0 |
business@2.1.0, ui@2.0.5(同 major 即可) |
bash
"access": "restricted"
含义:包的发布访问级别。
"restricted":私有包,只有授权用户才能安装(当前设置)"public":公开包,任何人都能安装
所以实际发布时,business 包是 public 的,其他包是 restricted 的。
注意 :这个值只是默认值 。如果某个包的 package.json 中单独设置了 publishConfig.access,会覆盖这个默认值。比如当前工程中 @bht-next/business 的 package.json:
bash
"publishConfig": {
"access": "public" // ← 覆盖了 config.json 的 "restricted"
}
3.3 日常开发(每个开发者)
只做一件事:pnpm changeset
bash
# 修改完代码后
pnpm changeset
🔄 Step 1/3 --- 选择要发布的包
? Which packages would you like to include?
◯ @bht-next/auth-keycloak
◉ @bht-next/business ← 空格勾选/取消
◯ @bht-next/composables
...
🔄 Step 2/3 --- 选择版本变更级别
? What kind of change is this for @bht-next/business?
major ← 不兼容的 API 修改(BREAKING CHANGE)
❯ minor ← 向下兼容的新功能
patch ← 向下兼容的 bug 修复
🔄 Step 3/3 --- 输入变更描述
? Please enter a summary for this change:
-
新增批量导入组件
-
支持 xlsx 解析
✔ Changeset added! → .changeset/tall-tigers-sing.md
bash
---
"@bht-next/business": minor
---
新增批量导入组件
支持 xlsx 解析
把这个文件提交到 Git:
bash
git add .changeset/tall-tigers-sing.md
git commit -m "feat(business): 新增批量导入组件"
3.4 发布阶段(在 master 分支上统一执行)
bash
# Step 1: 消费所有计划文件,更新版本号
pnpm changeset version
这一步自动完成:
- 读取所有
.changeset/*.md,合并同一包的多个变更 - 修改
package.json的version字段 - 更新
CHANGELOG.md - 删除已消费的
.md文件
bash
# Step 2: 提交版本变更
git add . && git commit -m "chore: release"
Step 3: 发布到 npm
pnpm changeset publish
这一步自动完成:
- 检测哪些包的本地版本 > npm 仓库版本
- 触发
prepublishOnly钩子 → 自动执行tsup构建 - 发布到 npm 仓库
核心口诀
开发者只管
changeset(声明意图),发布者统一version+publish(执行发布)。 记住这个分工,就不会用错。