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: 仅发布为公开的包(也就是package.json中没有设置 "private": true 的包)
  // 注意: 如果使用 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
          # 当我改为 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
  2. 登录到 verdaccio 服务, 登录成功后, 获得 ~/.npmrc 的 authToken 内容
  3. 在本地新建 .npmrc 测试 npm whoami 是否可以成功获取登录用户名, 成功说明 npmrc 文件配置正确
  4. 设置 package.json 的 publishConfig 的 registry 字段
  5. 设置 Github Actions secrets, 添加 NPM_TOKEN NPMRC GH_TOKEN 三个变量
  6. 修改 .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"
          # 直接使用默认的 version 和 publish 用默认的即可, 不需要额外配置

      # 删除动态前面步骤生成 .npmrc 文件
      - name: Clean up npmrc config
        run: |
          echo "Cleaning up..."
          rm -rf .npmrc
          ls -al
jsonc
"publishConfig": {
  // 注意实际的 packge.json 中不能有注释, 我这是为了记录笔记
  // 注意 package.json 中的名字在 verdaccio 中不能有重复的
  // 注意要和 .npmrc 中保持一致
  "registry": "https://yournpmjs.com"
},
txt
ghp_h6rWGk7ypjnDBQRvM1TcSZG9Qzg9XkXG
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.