Changeset 自动化发布
手动
npm version+npm publish在单包项目还行,Monorepo 有多个包互相依赖就乱了。Changeset 是 Monorepo 版本管理的标准方案。
为什么用 Changeset
Monorepo 发版的三个难题:
- 版本联动:core 发了 minor,依赖 core 的 vue 要不要发?发什么版本?
- CHANGELOG:每个包的变更日志手写不现实
- 发布顺序:core 必须先于 vue 发布,因为 vue 依赖 core
Changeset 解决方案:开发者每次改代码时描述改了什么(patch/minor/major + 说明),CI 自动根据这些描述计算版本、生成 CHANGELOG、按顺序发布。
安装与初始化
pnpm add -Dw @changesets/cli @changesets/changelog-github
pnpm changeset init
bash
Changesets v3(2026-08-11 发布,当前 3.0.x):七年来的首个大版本。要求 Node.js ≥ 22.11、pnpm ≥ 10 / npm ≥ 10.9 / Yarn ≥ 4.5.2;包体改为 ESM-only,依赖数从 95 降到 39(安装体积缩小 88%);peer 依赖的联动 bump 从 major 降为 patch;新增 pack、publish-plan 等命令支持 e18e 社区推荐的「build → pack → publish」流程。旧项目从 v2 升级先过一遍官方迁移指南(changesets.dev/guide/migration)。@changesets/changelog-github 当前 0.6.x。
初始化后生成 .changeset/config.json(ai-chat-ui 仓库的真实配置):
{
"$schema": "https://unpkg.com/@changesets/config@3.0.0/schema.json",
"changelog": "@changesets/cli/changelog",
"commit": false,
"fixed": [],
"linked": [],
"access": "public",
"baseBranch": "master",
"updateInternalDependencies": "patch",
"ignore": []
}
json
关键字段:
- access: "public",scoped 包默认私有,这里统一设置公开
- updateInternalDependencies: "patch",当 core 发新版时,vue 的 core 依赖自动升 patch
- baseBranch: "master",CI 比对用的基准分支(本仓库主分支叫 master,按实际分支名填)
- changelog: 默认
@changesets/cli/changelog不带链接;换成@changesets/changelog-github可在 CHANGELOG 里关联 commit/PR/作者(使用时需提供 GITHUB_TOKEN)
开发工作流
1. 改完代码后创建 changeset
pnpm changeset
bash
交互式选择:
- 哪些包有变更?(空格选择 @toimc/core)
- 版本类型?(patch / minor / major)
- 变更描述?(用中文写,会出现在 CHANGELOG)
生成文件 .changeset/happy-chat-123.md:
---
"@toimc/core": patch
---
修复 generateId 在高并发下的唯一性问题
markdown
2. CI 自动版本
在 CI 中(或本地手动)运行:
pnpm changeset version
bash
这会:
- 读取所有
.changeset/*.md文件 - 更新对应包的
package.jsonversion - 把描述写入
CHANGELOG.md - 删除已消费的 changeset 文件
3. 发布
pnpm changeset publish
bash
这会:
- 对每个版本号有变化的包执行
npm publish - 按依赖顺序发布(core 先于 vue)
- 输出发布的包名和版本号
发布后打 git tag 并推送:
git add .
git commit -m "chore: release packages"
git push --follow-tags
bash
GitHub Actions 自动发布
完整的自动化流程:PR 里创建 changeset → 合并后 CI 自动发版。
# .github/workflows/release.yml
name: Release
on:
push:
branches: [master]
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5 # v5 起 action 运行时为 Node 24(v4 是已淘汰的 Node 20)
- uses: pnpm/action-setup@v4
with:
version: 10 # Changesets v3 要求 pnpm ≥ 10
- uses: actions/setup-node@v5
with:
node-version: 22 # Changesets v3 要求 Node ≥ 22.11
cache: pnpm
registry-url: https://registry.npmjs.org # 写入 .npmrc,publish 认证用
- run: pnpm install --frozen-lockfile
- run: pnpm build
- run: pnpm test
# changesets/action@v2 兼容 Changesets v3;v2 不再自动写 .npmrc,
# 认证 = setup-node 的 registry-url + 这里的 NODE_AUTH_TOKEN
- name: Create Release Pull Request or Publish
uses: changesets/action@v2
with:
publish-script: pnpm changeset publish
version-script: pnpm changeset version
commit-message: "chore: release packages"
pr-title: "chore: release packages"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
yaml
这个 Action 做两件事:
- 有未消费的 changeset:创建一个 "Version Packages" PR,里面包含版本号变更和 CHANGELOG 更新
- 合并 Version Packages PR 后:自动执行
changeset publish发布到 npm。v2 默认还会在发布后创建 GitHub Releases 和 git tags(create-github-releases/push-git-tags输入可关)
实战仓库的发布流水线:tag 触发 + 双模式脚本
ai-chat-ui 仓库实际采用的自动化发布是另一种形态——git tag 触发 + scripts/publish.sh 双模式(手动版本 / changeset),由 01 节的 AI 首发实战固化而来:
# .github/workflows/publish.yml(仓库真实文件,节选关键步骤)
name: Publish to npm
on:
push:
tags: ['v*'] # 打 v 开头的 tag 才发布,日常 push 不触发
workflow_dispatch: # 也支持 Actions 页面手动触发
inputs:
version:
description: 'Version to publish (e.g., 1.0.0)'
required: true
type: string
use_changeset:
description: 'Use changeset mode'
type: boolean
default: false
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-node@v4
with:
node-version: '24'
registry-url: https://registry.npmjs.org
- uses: pnpm/action-setup@v4
with:
version: 11.21.0
- run: pnpm install --frozen-lockfile
- run: pnpm build
- run: |
pnpm test
pnpm type-check
- name: Publish to npm
run: |
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
if [ "${{ inputs.use_changeset }}" = "true" ]; then
./scripts/publish.sh --changeset
else
./scripts/publish.sh --manual "${{ inputs.version }}"
fi
else
VERSION=${GITHUB_REF#refs/tags/v}
./scripts/publish.sh --manual "$VERSION" --tag "$VERSION"
fi
env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
NPM_REGISTRY: https://registry.npmjs.org
yaml
与 changesets/action 的 Version PR 模式相比:tag 触发模式更「发版是显式动作」——什么时候发、发什么版本由打 tag 的人决定,适合单人课程项目;多人协作、发版频繁的团队更适合 Version PR 模式(PR 里 review 版本与 CHANGELOG)。两种模式可以并存。
更安全的选择:Trusted Publishing(OIDC)
npm 正在收紧长期 token(01 节提过:2027 年 1 月起 bypass-2FA token 不能直接 publish)。新项目的自动化发布建议直接上 Trusted Publishing,仓库里不存任何 npm token:
- npmjs.com 包设置 → Publishing access → Trusted Publishing:登记仓库(owner/repo)、workflow 文件名、environment(可留空)
- workflow 的
permissions加id-token: write(OIDC 令牌)与contents: read - CI 内的 npm 版本要新(≥ 11.5;
actions/setup-node的 node 22/24 自带 npm 10/11,必要时在发布步骤前npm install -g npm@latest) - 发布时 npm 自动向 GitHub 的 OIDC 端点换取短时令牌完成认证,并自动生成 provenance 溯源声明(包页出现 Provenance 徽标,标明「这个版本由哪次 CI 构建产出」),无需再加
--provenance参数
changesets/action v2 为 trusted publishing 暴露了 sub-actions(不在本课程展开,多包 monorepo 迁移 OIDC 时查官方 Automating Changesets 指南)。如果暂时不想动 CI,过渡方案是 npm 的 staged publishing:npm stage publish 把版本暂存,维护者网页/CLI 用 2FA 审批后正式生效——CI 里的 token 即使泄露也发不了包。
用 AI 管理 Changeset
> 我刚修改了 packages/core 的 generateId 函数和 packages/vue 的 Message 组件。
> core 是 bug 修复,vue 是新增了图片预览功能。
> 请帮我创建对应的 changeset。
text
AI 会运行 pnpm changeset 并根据变更内容自动选择包和版本类型。
排查发布问题:
> changeset publish 报错 403 Forbidden。
> 请帮我检查 npm token 配置和包的访问权限。
text
小结
- Changeset 解决 Monorepo 版本联动、CHANGELOG、发布顺序三大问题;v3(2026-08)要求 Node ≥ 22.11 / pnpm ≥ 10,ESM-only、安装体积 -88%、peer 依赖联动改 patch bump
- 工作流:改代码 →
pnpm changeset描述变更 →changeset version升版本 →changeset publish发布 - GitHub Actions 自动化两形态:changesets/action 的 Version PR 模式(合并即发布,v2 兼容 v3 并默认建 GitHub Releases/tags);tag 触发 +
scripts/publish.sh双模式(发版是显式动作,适合单人项目) - npm token 收紧是趋势:新项目优先 Trusted Publishing(OIDC + 自动 provenance),过渡期用 staged publishing
- AI 可以根据代码变更自动创建 changeset 并排查发布问题
下一节讲 Monorepo 发布策略——多包联动、package.json exports 设计、发布后的验证。
↑