是什么
流行的 monorepo 场景发包工具
Changesets 是一个用于 Monorepo 项目下版本以及 Changelog 文件管理的工具。目前一些比较火的 Monorepo 仓库都在使用该工具进行项目的发包例如 pnpm、mobx 等。
github 仓库为:
在 github 上有大约 7k 的 star。changesets 是用于管理版本及变更日志的工具,专注多包管理。
您可以为 monorepo 中的每个包定义一组更改和更新。这些更改可能包括错误修复、新功能、性能改进或任何其他修改。
为什么
它解决了单一存储库中管理版本的复杂性,提供了简单而高效的解决方案。
帮助
❯ npx changeset --help
Organise your package versioning and publishing to make both contributors and maintainers happy
Usage
$ changeset [command]
Commands
init
add [--empty] [--open]
version [--ignore] [--snapshot <?name>] [--snapshot-prerelease-template <template>]
publish [--tag <name>] [--otp <code>] [--no-git-tag]
status [--since <branch>] [--verbose] [--output JSON_FILE.json]
pre <enter|exit> <tag>
tag
cli提供了这些命令
flowchart LR 1["changesets"] 1 --> add 1 --> init 1 --> pre 1 --> publish 1 --> status 1 --> tag 1 --> version
Lerna 发包方案缺陷
- ignoreChanges 不能做到文件的完全忽略,存在优先级问题
- lerna version 根据 commit 以及 tag 更新出来的包版本不符合预期
- 生成的 CHANGELOG 文件信息不完整
- lifecycle scripts 经常命中一些用户自定义的 script(例如 publish 等)
- CI 中自动化发包场景需要很高的定制成本
- lerna 本身不支持 workspace 协议,导致基于 pnpm 开发的一些仓库无法使用
Changesets 工作流程介绍
changesets 主要关心 monorepo 项目下子项目版本的更新、changelog 文件生成、包的发布。一个 changeset 是个包含了在某个分支或者 commit 上改动信息的 md 文件,它会包含这样一些信息:
- 需要发布的包
- 包版本的更新层级(遵循 semver 规范)
- CHANGELOG.md 信息
典型的工作流程包括
- 创建changesets
npx changeset
此命令将打开一个交互式提示,允许您选择已更改的包并指定更改的类型
版本类型
1. Patch. 例如 1.0.1 -> 1.0.2
2. Minor 例如 1.0.1 -> 1.1.0
3. Major 例如 1.0.1 -> 2.0.0
- 计算新版本
创建changesets后,下一步是确定每个包的新版本。
- 发布更新的包
通过命令npx changeset publish
发布到npm或私服。 它还为版本创建 Git 标签,使您可以轻松跟踪和引用它们
安装
要开始使用changesets,您需要将其安装为开发依赖项。打开终端并导航到项目目录。运行以下命令以使用 npm 安装变更集
安装依赖
pnpm i @changesets/cli
"license": "ISC",
"devDependencies": {
"@changesets/cli": "^2.26.1",
❯ npx changeset init
🦋 Thanks for choosing changesets to help manage your versioning and publishing
🦋
🦋 You should be set up to start using changesets now!
🦋
🦋 info We have added a `.changeset` folder, and a couple of files to help you out:
🦋 info - .changeset/README.md contains information about using changesets
🦋 info - .changeset/config.json is our default config
如何添加版本发布到 GitHub
npm install --save-dev @changesets/changelog-github
子命令
init
初始化必要的文件和目录
flowchart LR 1["存储"] 1 --> .changeset 1 --> config.json
npx changeset init
🦋 Thanks for choosing changesets to help manage your versioning and publishing
🦋
🦋 You should be set up to start using changesets now!
🦋
🦋 info We have added a `.changeset` folder, and a couple of files to help you out:
🦋 info - .changeset/README.md contains information about using changesets
🦋 info - .changeset/config.json is our default config
该命令为初始化命令,通过执行 changeset init,可以在项目根目录下生成一个 .changeset 目录,里面会生成一个 changeset 的 config 文件
该命令原理相对简单,执行的时候通过 fs 将对应配置文件写到目录下就行,关于 config 中的具体配置描述可以参考
。init 初始化出来的为默认配置,一般不需要用户去做过多的修改。注意:
{
"$schema": "https://unpkg.com/@changesets/config@1.5.0/schema.json",
"changelog": [
"@changesets/changelog-github",// @changesets/changelog-github 是一个生成 changelog 的插件
{
"repo": "xxx" // 改为你的 github 仓储
}
],
"commit": false,
"linked": [],
"access": "public",
"baseBranch": "master",
"updateInternalDependencies": "patch",
"ignore": []
}
add
npx changeset add --type patch
❯ npx changeset add
🦋 Which packages would you like to include? …
◯ unchanged packages
◯ admin
◯ @cool-vue/layout
◯ @cool-vue/crud
add 在 changesets 中算得上比较关键的命令之一了,它会根据 monorepo 下的项目来生成一个 changeset 文件,里面会包含前面提到的 changeset 文件信息(更新包名称、版本层级、CHANGELOG 信息)。
会让我们选择本次 changeset 需要发布的包,这些包名都是 Monorepo 项目下的子包,changesets 内部通过 getPackages()
这一方法得到 Monorepo 项目下子项目信息
changesets 下面一个叫做 @manypkg/get-packages 的包。方法本质上是通过读 Monorepo 下所有子项目的 package.json 然后构建出一个依赖图出来,changesets 可以根据该结果得到需要进行发包流程的项目,可以说整个 changesets 项目本身都会基于底层这个方法来进行构建,有点类似于一般 Monorepo 工具中的 graph 构建。
demo
❯ npx changeset add
🦋 What kind of change is this for @test/utils? (current version is 0.0.0) …
❯ patch
minor
major
在软件开发中,"patch"、"minor"和"major"通常用来表示版本号的不同级别的更新
- "patch"(补丁)表示对软件进行小的修复或改进,通常是修复一些bug、漏洞或进行一些小的优化,不会引入新的功能。
- "minor"(次要)表示对软件进行一些较小的改进或增加一些新的功能,但仍保持向后兼容性,不会破坏现有的功能或接口。
- "major"(主要)表示对软件进行重大的改进、重构或引入了不向后兼容的变化,可能会破坏现有的功能或接口。
- pnpm changeset version:此命令会自动根据当前的变更类型(如 fix、feat、chore 等)来确定要发布的版本类型。如果变更类型是 fix,则会选择补丁版本(patch),如果是 feat,则会选择次要版本(minor),其他类型则为主要版本(major)。
- pnpm changeset version --type patch:此命令会强制选择补丁版本(patch)作为要发布的版本类型。
- pnpm changeset version --type minor:此命令会强制选择次要版本(minor)作为要发布的版本类型。
version
version
这个命令这里可以当作 bump version 来理解,这里本质上做的工作是消耗 changeset 文件并且修改对应包版本以及依赖该包的包版本,同时会根据之前 changeset 文件里面的信息来生成对应的 CHANGELOG 信息。
执行后子包的版本号会增加。
此命令将根据您的changesets计算新版本并更新package.json受影响的包的文件。此外,它还会为版本创建新的 Git 标签。
publish
➜ tl-cli git:(main) ✗ npx changeset publish --access publish
🦋 info npm info @taoya7/cleanup
🦋 info npm info @taoya7/commit-cli
🦋 info npm info @taoya7/i18n-cli
🦋 info npm info @taoya7/label-cli
🦋 info npm info @taoya7/cli-shebang
🦋 info npm info @taoya7/templates-cli
🦋 info npm info @taoya7/cli-ui
🦋 warn @taoya7/cleanup is not being published because version 1.0.11 is already published on npm
🦋 info @taoya7/commit-cli is being published because our local version (1.0.16) has not been published on npm
🦋 warn @taoya7/i18n-cli is not being published because version 1.0.11 is already published on npm
🦋 warn @taoya7/label-cli is not being published because version 1.0.12 is already published on npm
🦋 warn @taoya7/cli-shebang is not being published because version 1.0.11 is already published on npm
🦋 warn @taoya7/templates-cli is not being published because version 1.0.0 is already published on npm
🦋 warn @taoya7/cli-ui is not being published because version 1.0.11 is already published on npm
🦋 info Publishing "@taoya7/commit-cli" at "1.0.16"
🦋 success packages published successfully:
🦋 @taoya7/commit-cli@1.0.16
🦋 Creating git tag...
🦋 New tag: @taoya7/commit-cli@1.0.16
包的发布
这里需要注意的是,版本的选择一共有三种类型,分别是 patch、minor 和 major,严格遵循 semver 规范。
例子
❯ npx changeset publish
🦋 info npm info @test/utils
🦋 info @test/utils is being published because our local version (0.0.1) has not been published on npm
🦋 info Publishing "@test/utils" at "0.0.1"
🦋 success packages published successfully:
🦋 @test/utils@0.0.1
🦋 Creating git tag...
🦋 New tag: @test/utils@0.0.1
不提交某个包
如果你想在 Changesets 中选择性地提交某个包而不发布它,可以使用
--skip <packageName>
选项。这个选项允许你指定要跳过发布的特定包。
semver
常见的tag
名称 | 功能 |
---|---|
alpha | 是内部测试版,一般不向外部发布,会有很多Bug,一般只有测试人员使用 |
beta | 也是测试版,这个阶段的版本会一直加入新的功能。在Alpha版之后推出 |
rc | Release Candidate) 系统平台上就是发行候选版本。RC版不会再加入新的功能了,主要着重于除错 |
pnpm changeset pre enter beta
之后在此模式下的 changeset publish 均将默认走 beta 环境,下面在此模式下任意的进行你的开发
# 1-1 进行了一些开发...
# 1-2 提交变更集
pnpm changeset
# 1-3 提升版本
pnpm version-packages # changeset version
# 1-4 发包
pnpm release # pnpm build && pnpm changeset publish --registry=...
# 1-5 得到 1.0.0-beta.1
# 2-1 进行了一些开发...
# 2-2 提交变更集
pnpm changeset
# 2-3 提升版本
pnpm version-packages
# 2-4 发包
pnpm release
# 2-5 得到 1.0.0-beta.2
完成版本发布之后,退出 Prereleases 模式
$ pnpm changeset pre exit
参考
semver规范