首页
/ Material UI 发布与文档部署实战指南:面向 monorepo 的版本发布、Hotfix 与免发布文档上线全流程

Material UI 发布与文档部署实战指南:面向 monorepo 的版本发布、Hotfix 与免发布文档上线全流程

2026-09-07 09:18:39作者:吴年前Myrtle

导读

本指南基于 scripts/README.md,系统讲解 Material UI 当前 monorepo(仓库根版本见 package.json,当前为 9.4.0)从版本准备、Changelog 生成、npm 发布、GitHub Release、文档部署到公告的完整发布 SOP(标准操作流程)。文中不仅完整保留原文档的全部操作步骤与命令参数,还结合根目录 package.jsonscripts/releaseChangelog.mjsscripts/releasePack.mtsscripts/canaryRelease.mts.github/workflows/publish.yml 等源码与 CI 配置,补充命令底层实现细节,使读者既能照着执行一次 minor/hotfix 发布,也能理解每条命令背后究竟发生了什么。

适用读者:Material UI monorepo 的维护者与贡献者,以及任何希望理解“大型 pnpm workspace + Lerna + GitHub Actions”发布链路的技术人员。


一、发布前置准备:远程仓库与 GitHub Token

在开始任何一次发布之前,需要先完成两项一次性配置。

1. 添加两个 Git Remote

文档部署与发布流程依赖两个远程仓库,一个用于同步上游代码,一个用于推送构建后的文档站点:

git remote add upstream https://github.com/mui/material-ui.git
git remote add material-ui-docs https://github.com/mui/material-ui-docs.git

其中 upstream 指向官方主仓库,material-ui-docs 是承载文档站点构建产物的仓库——它的各分支(latestnextv*.x)分别对应不同版本的 mui.com 站点。

2. 生成 GitHub Token

文档原文要求在 GitHub 的设置页生成个人访问令牌,并写入 shell 配置(.bashrc.zshrc)中的环境变量 GITHUB_TOKEN;若使用 Classic Token,需为其勾选 repo:public 权限范围。

scripts/releaseChangelog.mjs 的源码可以看到,脚本运行时优先读取 GITHUB_TOKEN 来初始化 Octokit 客户端,用于访问 GitHub API 拉取提交信息:

octokit: process.env.GITHUB_TOKEN
  ? new Octokit({ auth: process.env.GITHUB_TOKEN })
  : undefined,

同时脚本会对从环境变量读取 Token 的做法给出废弃警告("Using GITHUB_TOKEN from environment variables have been deprecated"),并提示:若本地设置了该变量应移除,优先通过命令参数 --githubToken <my-token> 传入(见下文)。这也说明实际操作时应以最新版脚本帮助信息为准。


二、发布一个 minor 版本

minor 版本(月度功能发布)遵循如下节奏:先以 PR 形式完成准备工作 → 通过 GitHub Actions 手动触发发布 → 部署文档 → 发布 GitHub Release → 公告

阶段一:Prepare(必须通过 PR 提交)

以下步骤的产物(版本号变更 + Changelog)必须以 Pull Request 形式提出,等待审查与 CI 通过:

第 1 步:拉取上游标签

git fetch upstream --tags

这一步保证本地拥有完整的 tag 历史,供后续 Changelog 脚本定位“上一个发布版本”。

第 2 步:更新根目录版本号

修改仓库根 package.json 中的 "version" 字段(当前仓库该字段为 "9.4.0")。它是整个 monorepo 的版本基准。

第 3 步:生成 Changelog

pnpm release:changelog

package.json 中该命令的定义为 node scripts/releaseChangelog.mjs。生成结果需要前置拼接到仓库顶层的 CHANGELOG.md 中。

可通过 pnpm release:changelog --help 查看该命令的全部参数。源码 scripts/releaseChangelog.mjs 展示了核心的两个选项:

选项 含义 默认值
--lastRelease 作为对比基准的版本(如 v5.0.0-alpha.23 当前分支上的最新 tag
--release 本次要发布的 ref master

GITHUB_TOKEN 不在环境变量中,可将 Token 作为参数传入:pnpm release:changelog --githubToken <my-token>

该脚本的底层逻辑(见 scripts/releaseChangelog.mjs)值得展开说明,方便你理解生成的 Changelog 结构:

  • 通过 @mui/internal-code-infra/changelogfetchCommitsBetweenRefs 获取两个 ref 之间的提交,并过滤掉机器人提交([bot] 结尾的 login)和以 [website] 开头的提交
  • 解析每条 commit message 开头的方括号标签(如 [Slider][docs]),将标签转小写、升序排列后按组归类排序提交;
  • 对没有 PR 链接(正则 /\(#[0-9]+\)$/)的提交,追加 7 位 commit SHA 以便追溯;
  • 自动统计贡献者数量并生成“按字母序排列的贡献者名单”;
  • 版本号从当前 package.jsonversion 字段读取,输出模板中预留了 TODO INSERT HIGHLIGHTS 占位符,提醒维护者手动补写 release 亮点。

第 4 步:人工清理生成的 Changelog

  1. 使格式与仓库 GitHub Releases 页面的既有格式保持一致;
  2. 如适用,将包名大小写改为小写(便于与 npm 包名统一)。

第 5 步:提升各包版本号

pnpm release:version

package.json 中该命令定义为:

lerna version --no-changelog --no-push --no-git-tag-version --no-private --force-publish=@mui/core-downloads-tracker

它基于 Lerna 工作。执行时务必留意两条规则:

  1. 只有自上版以来确有变更的包才应被提升版本;
  2. 有变更且遵循 Material-UI 版本体系的包,应提升到与根 package.json 相同的版本——这可能需要跳过某些中间版本号(即“对齐到根版本”),因为各包发布节奏并不完全一致。

第 6-7 步:提交 PR

打开包含以上变更的 PR,等待审查与 CI 全绿后合入 master。合入后记住该 merge commit 的 SHA,后续发布工作流需要用到。

阶段二:Release(通过 GitHub Actions 触发)

  1. 前往仓库的 Publish packages workflow(对应仓库文件 .github/workflows/publish.yml);
  2. 点击 “Run workflow” 下拉框,填入以下输入项:
输入项 说明
Branch 固定为 master
Commit SHA to release from 包含已合入 release 变更的 master 提交(该提交与后续 GitHub Release 相关联)
Run in dry-run mode 调试用,勾选后不会真正发布
Create GitHub release 保持勾选,将依据 Changelog 自动创建 GitHub Release 草稿
npm dist tag to publish to 用于发布 legacy 或 canary 版本(如 nextlegacy

.github/workflows/publish.ymlworkflow_dispatch 输入定义可见,完整输入还包括 internal-packages(是否仅发布内部包),且各输入默认值清晰:dry-run 默认 falsegithub-release 默认 truedist-tag 默认 latest

  1. 点击 “Run workflow” 后刷新页面,点击新创建的 workflow run;
  2. 随后页面会出现 "@username requested your review to deploy to npm-publish" 的环境保护提示,需要点击 “Review deployments” 并授权该次 workflow run。务必只授权你自己发起的 workflow run——这是 npm 发布环境的安全门禁。

阶段三:部署文档

minor 版本发布后,执行:

pnpm docs:deploy

package.json 将该命令转发给 docs 包的 deploy 脚本,即 docs/package.json 中定义的:

git fetch upstream master && git push -f material-ui-docs FETCH_HEAD:latest

可见其本质是把上游 master 最新内容强制推送到 material-ui-docs 仓库的 latest 分支,触发静态站点(Netlify 上部署的 mui.com)更新。必要时允许 force push。注意:这一步使用 force push 属于该流程的既定设计,用于让 docs 分支始终与目标提交精确对齐。

阶段四:发布 GitHub Release

文档部署完成后,在 GitHub Releases 页面审查之前自动创建的 draft Release(依据你勾选的 “Create GitHub release”),确认无误后点击发布。此时 release tag 才被创建——即 tag 在流程末尾落地,早于 tag 的发布操作没有意义。

阶段五:公告

文档站点生效后,按照项目维护团队内部发布的公告清单执行 Announce 步骤(邮件、社交媒体、内部渠道等)。


三、发布一个 hotfix 版本

Hotfix 适用于:线上有回归缺陷亟待修复,等不及下一个月度 minor 发布周期,而 master 上又已积累了暂未发布的提交(这些提交不能一起带出去)。如果更早的 minor 或 patch 可以直接发布,文档明确建议优先用常规发布而非 hotfix。

阶段一:Prepare

创建 hotfix 分支需要仓库管理员协助,步骤如下:

  1. checkout 到最新 release tag 对应的提交;
  2. 创建名为 release/<PATCH_VERSION> 的分支,其中 <PATCH_VERSION> 是从该 release tag 起算的下一个 semver patch 版本号(例如上个 tag 是 v9.4.0,则分支名为 release/9.4.1);
  3. 将分支强制推送到 upstream
git push -f upstream release/<PATCH_VERSION>

后续步骤同样必须以 PR 形式提交到 release/<PATCH_VERSION> 分支:

  1. checkout 该分支,并在其上 cherry-pick 需要修复的 hotfix 提交

  2. 生成 Changelog(命令与 minor 流程一致,同样支持 --githubToken 传参):

    pnpm release:changelog
    

    输出同样前置拼接到根 CHANGELOG.md

  3. 人工清理 Changelog:格式对齐 GitHub Releases 页面、包名大小写统一为小写;

  4. 更新根 package.jsonversion 为 patch 版本号;

  5. 执行 pnpm release:version,遵循与 minor 流程相同的两条规则(仅提升有变更的包、同步到根版本号,必要时跳过中间版本);

  6. 打开 PR 等待审查与 CI;

  7. CI 全绿且获批后合入 release/<PATCH_VERSION>

  8. 再从 release/<PATCH_VERSION> 打开并合入一个回到 master 的 PR,用于回写正确的包版本并更新 Changelog(因为 master 上本次未走常规发布,需要把版本状态对齐)。

阶段二:发布

hotfix 分支合入后,同样通过 “Publish packages” 工作流手动触发,区别在于选择的 commit SHA 来自 release/<PATCH_VERSION> 分支上的合入提交,随后走与 minor 相同的 Review deployments 授权步骤。

阶段三:部署文档

hotfix 的文档部署不走 pnpm docs:deploy(那是 master 语义),而是直接推送到 docs 仓库:

git push -f material-ui-docs HEAD:latest

阶段四:发布 GitHub Release

发布步骤中 workflow 会自动创建 draft Release;文档部署完成后审查并发布该草稿。

阶段五:Cleanup

发布完成后把 release/<PATCH_VERSION> 分支合并回 master。合入时注意解决冲突——master 在此期间可能已对相同文件产生后续改动。

阶段六:公告

文档上线后,同样执行公告清单。


四、执行 npm 包发布与 GitHub Release

无论 minor 还是 hotfix,最终“真正把包推送到 npm”这一步既可交给上述 GitHub Actions 工作流,也可在本地通过命令完成(两种方式殊途同归,本地命令本质是触发同一套发布逻辑)。

pnpm release:publish

命令说明与参数

package.json 中的定义:

"release:publish": "code-infra publish --github-release",
"release:publish:dry-run": "code-infra publish --github-release --dry-run",

code-infra 是 MUI 内部的代码基础设施 CLI(来自 @mui/internal-code-infra 依赖),--github-release 标志表示发布后创建 GitHub Release。

执行要点:

  1. 首次运行(或间隔很久)时,可能会要求先通过 GitHub 认证;

  2. 命令会自动拉取最新已合入的 release PR,并在发布前要求你确认

  3. 若已知道要发布的 commit SHA,可直接传入,跳过交互式确认:

    pnpm release:publish --sha <your-sha>
    
  4. 其他可用标志:

标志 用途
--dry-run 调试用,不真正发布;等价于直接运行 pnpm release:publish:dry-run
--dist-tag 发布 legacy 或 canary 版本时指定 npm dist-tag
  1. 该命令会调用 .github/workflows/publish.yml 中定义的 Publish GitHub Action,并打印出 workflow run 的 URL 供追踪;
  2. 同样需要进入工作流页面,点击 “Review deployments” 授权本次发布。再次强调:不要批准任何非你发起的 workflow run。

其他辅助发布命令

仓库中还配套了另外两个发布相关命令,可结合需要了解:

  • pnpm release:pack(定义于 package.json,实现见 scripts/releasePack.mts):将各公开 workspace 执行 pnpm pack 打包为 .tgz./packed 目录(可用 --packages--outDir--concurrency 调整),并生成 manifest.json,用于发布前的产物校验,默认只打包非 private 的公开包;
  • pnpm canary:release(定义于 package.json,实现见 scripts/canaryRelease.mts):面向 canary 版本,通过 pnpm list --filter ...[baseline] 找出相对基线(默认 git describe --abbrev=0 的最新 tag)变更的公开包,自动改写版本号为 <version>-dev.<yyyyMMdd-HHmmss>-<short-sha> 后以 --tag canary 发布。工作流层面则由 .github/workflows/publish-canaries.yml 承接。

五、不发布版本的情况下单独部署文档

有些场景需要只部署选中的某些提交,而不携带自上次发布以来合入 master 的全部变更(例如发布一篇博客文章,或紧急修复文档站点)。此时可绕过“发布循环”,直接向 material-ui-docs 仓库的指定分支推送。

分支与站点子域名对应关系

目标分支 对应站点
latest https://mui.com/
next https://next.mui.com/
v*.x https://v*.mui.com/(如 v5.x 对应当前 master 之外的归档站点)

若需部署到不同子域名,将下面命令中的 latest 替换为对应分支名即可。

操作步骤

1. 添加 remote(若尚未添加):

git remote add material-ui-docs https://github.com/mui/material-ui-docs.git

2. 拉取目标分支最新内容

git fetch material-ui-docs latest

3. 切换到 detached HEAD(以 material-ui-docs/latest 为基准,避免干扰本地分支):

git switch --detach material-ui-docs/latest

4. Cherry-pick 需要纳入本次部署的提交

git cherry-pick <commit>

无冲突时命令会自动完成提交;有冲突则需手动解决冲突后手动提交。

若命令报 bad revision,说明该提交不存在于本地仓库——它可能产生于远程分支(通常在合入 masterv*.x 时创建),此时先 fetch 对应远程分支的最新内容再重试即可。

5. 推送到 material-ui-docs 远端

git push material-ui-docs HEAD:latest

6. 切回原分支(退出 detached HEAD 状态):

git checkout -

六、发布流程速查表与关键文件索引

为便于快速查阅,下表汇总本文全部核心命令及其底层定义位置:

操作 命令 实现位置
生成 Changelog pnpm release:changelog [--githubToken ...] [--lastRelease ...] [--release ...] package.json / scripts/releaseChangelog.mjs
提升各包版本 pnpm release:version package.json(Lerna)
发布包 + GitHub Release pnpm release:publish [--sha ...] package.json
发布演练 pnpm release:publish:dry-run package.json
打包产物校验 pnpm release:pack package.json / scripts/releasePack.mts
发布 canary pnpm canary:release package.json / scripts/canaryRelease.mts
minor 后部署文档 pnpm docs:deploy package.json / docs/package.json
hotfix/免发布部署文档 git push -f material-ui-docs HEAD:latest
手动触发 CI 发布 Publish packages 工作流 .github/workflows/publish.yml

整个流程的核心闭环可以概括为:master(或 release/<PATCH_VERSION>)上以 PR 完成“版本号 + Changelog + 包版本对齐” → 合入后手动触发 Publish workflow(携带精确 SHA 与 dry-run/dist-tag 等开关)→ 授权 npm-publish 环境 → 部署文档站点 → 发布 GitHub Release(tag 在此落地)→ 公告

需要特别留意三个易错点:其一,release tag 是在发布 GitHub Release 时才创建的,不要提前打 tag;其二,只批准自己发起的发布工作流,这是 npm 凭证环境的最后一道防线;其三,文档部署的 latest/next/v*.x 分支语义不同,免发布部署时务必选对分支,避免把未发布内容错推到 mui.com 主站。


结语

本文完整继承了 scripts/README.md 的全部发布操作细节,并补充了各命令在 package.jsonscripts/releaseChangelog.mjsscripts/releasePack.mtsscripts/canaryRelease.mts.github/workflows/publish.yml 中的底层实现与参数定义。如果你正在为 Material UI monorepo 准备下一次 minor 或 hotfix 发布,可直接按本文的“Prepare → Release → Documentation → Publish GitHub release → Cleanup/Announce”五段式流程推进;如果你只是希望单独上线文档内容,第四节“免发布部署”是最轻量的路径。实际执行任何命令前,建议结合当前仓库版本再次核对参数帮助输出(如 pnpm release:changelog --help),因为仓库工具链会随版本演进而调整。

登录后查看全文
热门项目推荐
相关项目推荐