Skip to content

changeset 是什么?

changeset 是专注于管理版本号和变更日志的工具, 尤其擅长处理多包仓库(monorepo)的版本/更新日志管理

changeset 和 semantic-release 的区别

  1. monorepos 支持
    • Changesets: 是专门为 monorepo 设计的,它能够更好地管理仓库内的多个包及其相互之间的依赖关系
    • Semantic-Release: 更加专注单仓库的版本控制,而在处理 monorepo 方面则不是特别好用
  2. 更新信息存储方式
    • Changesets: 会将变更信息写入 .changeset 目录的 markdown 文件, 且可以手动修改它
    • Semantic-Release: 从 git 的文件中读取并解析变更信息, 也就是说提交 git 后不能手动修改它
  3. CI 环境逻辑
    • Changesets: 会根据 changeset 变更信息文件中创建一个 pull-request, 然后由维护者去决定是否要合并
    • Semantic-Release: 直接根据 git 提交记录更新 package.json version 字段 & 创建新的 git commit 记录

主要功能

  1. 检查变更状态
  2. 生成变更信息文件 -> 简化手动变更版本的流程(monorepo 项目,手动修改的话,容易出错) -> 生成 CHANGELOG
  3. 集成 github Actions -> 自动创建 PR

Changesets 的基本工作流程

1. 安装

sh
# for monorepo
pnpm install -wD @changesets/cli

# for single repo
pnpm install -D @changesets/cli

2. 初始化

sh
pnpm changeset init

3. 创建一个变更记录信息

会在当前目录创建 .changeset 目录, 如果是monorepo, 会在所有子包中添加 CHANGELOG.md

sh
pnpm changeset add

4. 执行变更版本

执行后需要选择需要更新的版本类型, 自动更新 major.minor.patch 数值

sh
pnpm changeset version

5. 发布到 npm

执行后发布到 npmjs.com, 当然也可以通过 .npmrc 配置发布到 npm 私服

sh
yarn changeset publish

Changesets 配置

jsonc
{
  // 加上这个可以在写配置获得代码提示
  "$schema": "https://unpkg.com/@changesets/config@3.1.1/schema.json",

  // 如何生成 changelog 信息, 设置为 false 可以禁用这功能
  "changelog": "@changesets/cli/changelog",

  // 修改版本后, 是否提交文件
  "commit": true,

  // 多个包进行版本同步升级
  "fixed": [],

  // 多个包使用同一个版本, 功能类似 fixed 但是不同
  "linked": [],

  // 是否发布 package 中有 "private":true 的包
  // 允许的值为:
  //    - restricted: 发布私有包
  //    - public: 仅发布为公开的包,任何人都可以下载(推荐建议使用)
  // 注意: 如果使用 changeset publish 命令来发布到 verdaccio 私服, 需要将这个
  // 值设置为 public, 否则 {"name": "tools"} 这样的包名会发布失败, 错误信息如下:
  // error an error occurred while publishing tools: EUNSCOPED Can't restrict access to unscoped packages.
  // 如果非要设置为:  restricted, 需要将包名修改为 "@xxx/tools"
  "access": "public",

  // git 分支名(最好不要修改)
  "baseBranch": "main",

  // 是否需要更新子包依赖的包, 比如: packageA 依赖于 packageB
  // 此时 packageB 版本更新后, packageA 也自动更新版本
  "updateInternalDependencies": "patch",

  // 忽略哪些不需要 changeset 管理的包, 比如一些公共配置
  "ignore": [],
}

集成 Github Actions 自动创建 PR

  1. 安装 changeset bot
  2. 配置 github actions secrets, 可参考 semantic-release 的配置方式
  3. 配置 .github/workflows/changesets-create-pr.yaml
txt
.
├── README.md
├── apps
│   └── web
│       ├── CHANGELOG.md
│       ├── index.html
│       ├── package.json      # name: @for-study/web
│       ├── public
│       │   └── vite.svg
│       ├── src
│       │   ├── App.vue       # 这个依赖 packages/tools/src/index.js 模块
│       │   └── main.js
│       └── vite.config.js
├── package.json              # name: @for-study/root
├── packages
│   └── tools
│       ├── CHANGELOG.md
│       ├── package.json      # name: @for-study/tools
│       └── src
│           └── index.js
├── pnpm-lock.yaml
└── pnpm-workspace.yaml

8 directories, 15 files
yaml
name: Changesets

on:
  push:
    branches:
      - main
    # 这些路径对应的文件变化之后才会触发这个 workflow
    paths:
      - ".changeset/**/*.md"
      - "packages/**/package.json"

concurrency: ${{ github.workflow }}-${{ github.ref }}

jobs:
  changesets:
    name: Changesets
    runs-on: ubuntu-latest
    # 权限设置
    permissions:
      contents: write
      packages: write
      pull-requests: write
    steps:
      # 1. 下载代码
      - name: Checkout
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

      # 2. 安装 pnpm
      - name: Install pnpm
        uses: pnpm/action-setup@v4
        with:
          version: 10.10.0
          run_install: false

      # 3. 安装 nodejs 22
      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 22
          cache: "pnpm"

      # 4. 使用 pnpm 安装 依赖
      - name: Install dependencies
        run: pnpm install

      # 5. 使用 changesets/action 消费版本变更信息文件
      - name: Create PR and publish
        id: changesets
        uses: changesets/action@v1
        env:
          GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
        with:
          # 创建 pr 时的提交信息和 pr 的 title
          commit: "chore(changeset): update versions"
          title: "chore(changeset): update versions"

          # publish: 默认会执行 pnpm changeset publish --tag
          # 当我改为 pnpm changeset tag 之后就不会发布到 npmjs.com
          publish: pnpm changeset tag

          # 是否将代码发布到 github release, 默认值为 true
          # 但是必须要 publish 步骤执行成功后才会执行发布到 github release 这个步骤
          # 假如使用默认的 publish 步骤会失败(因为没有配置 NPM_TOKEN)
          createGithubReleases: true

创建PR后自动发布到私有 npm 服务

为什么需要将内容发布到私服

  1. 在 npmjs.com 上, 创建组织是收费的功能
  2. 有的代码可能是公司内部用的, 而不是开源的

发布到私有仓库需要满足哪些条件?

  1. 首先, 必须要有一个公网可以访问的 verdaccio 私服, 搭建教程, 假设服务为 https://yournpmjs.com
    1. 在本地登录私有服务 npm login --registry https://yournpmjs.com
    2. 获得本地 ~/.npmrcauthToken 内容 设置到 github actions 的 secrets 中
  2. 将 registry 和 authToken 登录信息(NPMRC)都设置到 github action secrets
  3. 设置 package.jsonpublishConfigregistry 字段
  4. 修改 .github/workflows/changesets-create-pr.yaml 内容如下:
yaml
name: Changesets

on:
  push:
    branches:
      - main
    paths:
      - ".changeset/**/*.md"
      - "packages/**/package.json"

concurrency: ${{ github.workflow }}-${{ github.ref }}

jobs:
  changesets:
    name: Changesets
    runs-on: ubuntu-latest
    permissions:
      contents: write
      packages: write
      pull-requests: write
    steps:
      - name: Checkout
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Install pnpm
        uses: pnpm/action-setup@v4
        with:
          version: 10.10.0
          run_install: false

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 22
          cache: "pnpm"

      - name: Install dependencies
        run: pnpm install --frozen-lockfile

      # 动态生成 npmrc 配置文件
      - name: Generate npmrc config
        run: echo "${{ secrets.NPMRC }}" > .npmrc

      # ls -al 是用来查看 .npmrc 文件是否正常生成
      # npm whoami 可以用来验证 .npmrc 是否配置正确
      - name: Validate npmrc config
        run: |
          echo ">>> files" && ls -al
          echo ">>> whoami" && npm whoami

      - name: Create PR or publish release
        id: changesets
        uses: changesets/action@v1
        env:
          GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
          NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
        with:
          commit: "chore(changeset): update versions"
          title: "chore(changeset): update versions"

      # 删除动态前面步骤生成 .npmrc 文件
      - name: Clean up npmrc config
        run: |
          echo "Cleaning up..."
          rm -rf .npmrc
          ls -al
yaml
"publishConfig": {
  "registry": "https://yournpmjs.com"
},
txt
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyZWFsX2dyb3VwcyI6WyJhZG1pbiJdLCJuYW1lIjoiYWRtaW4iLCJncm91cHMiOlsiYWRtaW4iLCIkYWxsIiwiJGF1dGhlbnRpY2F0ZWQiLCJAYWxsIiwiQGF1dGhlbnRpY2F0ZWQiLCJhbGwiXSwiaWF0IjoxNzQ2MDM0NjcxLCJuYmYiOjE3NDYwMzQ2NzIsImV4cCI6MTc0ODYyNjY3MX0.7-Wuwd064uyl_spIBsMX4IMussoeP5SVhXOG1IxySck
txt
registry=https://yournpmjs.com
//yournpmjs.com/:_authToken=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyZWFsX2dyb3VwcyI6WyJhZG1pbiJdLCJuYW1lIjoiYWRtaW4iLCJncm91cHMiOlsiYWRtaW4iLCIkYWxsIiwiJGF1dGhlbnRpY2F0ZWQiLCJAYWxsIiwiQGF1dGhlbnRpY2F0ZWQiLCJhbGwiXSwiaWF0IjoxNzQ2MDM0NjcxLCJuYmYiOjE3NDYwMzQ2NzIsImV4cCI6MTc0ODYyNjY3MX0.7-Wuwd064uyl_spIBsMX4IMussoeP5SVhXOG1IxySck

容易出错点:

  • npmrc 内容中的 registry 必须和 package.json 中的 publishConfig.registry 字段保持一致, 否则报错
  • npmrc 总是无法通过验证, 可以在本地新建一个 .npmrc 然后使用 npm whoami 来验证是否能够狗正确获取到登录的用户名

Released under the MIT License.