Skip to content

Monorepo 发布工具对比调研(2026-08)

调研日期:2026-08-02 | 用途:评估 dependfix(pnpm workspace monorepo)的发布工具选型与 changelog 格式方案

演进注记(2026-08-10):本调研的结论"保持 changesets + 自研 changelog"已进一步演进——changeset 的剩余职责(版本提升执行 + 依赖传导 + 遍历发布)也由自研脚本替代(release:plan / release:version / release:publish,见发布管线设计发布指南),changeset 已完全移除。调研中"changesets 的 changelog 自定义能力最弱"与"semantic-release monorepo 硬伤"两个结论仍是演进方向的依据:changelog 走 conventional-changelog-cmyr 生态(同 momei 格式)、版本与发布自研(规避 semantic-release 的多包独立版本问题)。

结论摘要

  1. changesets 的 changelog 自定义能力最弱getReleaseLine/getDependencyReleaseLine 只能定制条目,版本标题(## x.y.z)与分组标题(### Major/Minor/Patch Changes)在 @changesets/apply-release-plan@7.1.1 源码(dist/changesets-apply-release-plan.esm.js:173:120)中写死
  2. semantic-release 的 changelog 与用户习惯格式天然契合@semantic-release/release-notes-generatorconfig 选项可直接挂载自定义 conventional-changelog preset(如 conventional-changelog-cmyr-config),momei 的 CHANGELOG 格式即由此生态生成;但 semantic-release 原生不支持 monorepo 多包独立版本,是其硬伤。
  3. Nx Release 自定义能力最强(自定义 renderer + 分组标题自定义),但要求引入整个 Nx 工具链,对仅需发布能力的项目过重。
  4. 对 dependfix 的建议:保持 changesets(版本管理 + 发布 + OIDC 已落地),changelog 生成采用"禁用 changesets changelog + 用 conventional-changelog-cmyr-config 生成"的混合方案,可获得与 momei 完全一致的日志格式,且不引入新发布工具。

一、工具总览与活跃度(数据日期:2026-08-02,GitHub API)

工具定位Stars最近活跃周下载量*
changesets文件式版本管理(.changeset/*.md)12,2102026-08-02~3M
semantic-release全自动、commit 驱动23,9342026-08-02~2M
release-it交互式手动发布 CLI9,0172026-07-31~2M
Lerna经典 monorepo 版本/发布(现由 Nx 驱动)36,0532026-07-31
Nx ReleaseNx 内置发布能力29,1702026-08-01
release-pleaseGoogle 的 release PR 自动化7,2812026-07-31

* 周下载量为 pkgpulse 2026-03 对比文章 引用的 npm registry 数据(2026-02 周均),为第三方数据。

全部工具均为 MIT 许可证(release-please 为 Apache-2.0),均在维护中。Lerna 曾长期维护停滞(2022 年 Nx 团队接管),目前 9.x 由 Nx 引擎驱动、9.0.7(2026-03-13) 仍在发布。


二、核心对比矩阵

维度changesetssemantic-releaserelease-itLerna 8/9Nx Release
Monorepo 多包独立版本✅ 一等公民❌ 原生不支持(issue #1688,需 community 插件或逐包 workflow)⚠️ 有限(issue #516 多包发布为痛点)✅ fixed/independent 两种模式✅ 一等公民(release groups / 独立版本)
Changelog 数据源.changeset/*.md 开发者意图conventional commit 消息conventional commit 消息(插件)conventional commit(--conventional-commits)或手动conventional commit 消息 + version plans(changeset 风格文件)
版本状态存放package.jsongit tags(不写 package.json,运行期取版本困难package.jsonlerna.json / package.jsonpackage.json
Changelog 条目自定义getReleaseLine/getDependencyReleaseLine 模块writerOpts/parserOpts/transform 扩展writerOpts 模板函数(commitPartial 等)⚠️ 依赖 conventional-changelog 配置✅ renderOptions + 自定义 commit types
Changelog 版本标题自定义❌ 写死 ## x.y.z✅ preset 模板(headerPartial)✅ preset 模板⚠️ 同上versionTitleDate 开关 + 自定义 renderer(Nx 22+)
Changelog 分组标题自定义❌ 写死 ### Major/Minor/Patch Changes✅ preset 的 commitGroups(中文 emoji 分组即此机制)preset.types[].section⚠️ 同上Customize Conventional Commit Types(section title 可改)
完全自定义 renderer⚠️ 需自建 preset⚠️ 模板函数可覆盖大部分⚠️自定义 ChangelogRenderer 类(Nx 22+,renderMarkdown 全权控制)
pre-releasepre 模式 + --snapshot分支驱动(beta 分支)--preRelease 参数内置支持
发布底层changeset publish(调 npm/pnpm publish)@semantic-release/npmnpm/yarn/pnpmlerna publish(npm)nx release publish
OIDC trusted publishing✅(底层 npm/pnpm publish 支持)✅(npm 插件走 npm CLI)✅(走 npm CLI)⚠️ 文档称始终用 npm 发布

三、Changelog 生成与自定义能力详解

3.1 changesets(当前 dependfix 所用)

  • 生成机制changeset version 消费 .changeset/*.md,写入每个包目录CHANGELOG.md@changesets/apply-release-plan@7.1.1 源码 path.resolve(dir, "CHANGELOG.md"))。
  • 自定义边界(本项目本地 node_modules@changesets/apply-release-plan@7.1.1 源码实证):
    • 版本标题:## ${release.newVersion}(apply-release-plan esm.js:173,写死)
    • 分组标题:### ${startCase(type)} Changes### Major Changes / ### Minor Changes / ### Patch Changes(esm.js:120,写死,无 changelogTypes 配置)
    • 条目:由配置的 changelog 模块(@changesets/changelog-github 或自定义模块路径)输出,可完全定制
  • 格式限制根源:changeset 只有 major/minor/patch 三种类型维度,没有 commit type(feat/fix/refactor)维度,无法还原 conventional-changelog 的 emoji 中文分组。
  • 禁用方式.changeset/config.jsonchangelog 字段支持 falseconfig schema 确认)。
  • 参考实现:react-turnstile(pnpm + changesets 2.31.1 + OIDC 生产案例)。

3.2 semantic-release(用户生态:momei / semantic-release-cmyr-config)

  • 生成机制@semantic-release/release-notes-generator 用 conventional-changelog 从 commit 消息生成 release notes,@semantic-release/changelog 写入 CHANGELOG.md
  • 自定义能力官方 README):
    • configNPM 包名形式的自定义 conventional-changelog preset——conventional-changelog-cmyr-config 直接可用(semantic-release-cmyr-config 即如此配置)
    • parserOpts / writerOpts:在 preset 之上逐项覆盖
    • linkCompare / linkReferences / host / commit / issue:链接生成控制
  • 格式:由 preset 模板决定——momei 的 # [1.25.0](compare) (2026-08-01) + ### ✨ 新功能 + * **scope:** desc ([hash](链接))conventional-changelog-cmyr-config@3.0.0 模板templates/header.hbscommit.hbs)的输出。
  • monorepo 硬伤官方 issue #1688(NPM 7 workspaces 支持请求)长期 open;多包独立版本需 semantic-release-monorepo 等社区方案,配置复杂,且全自动 bump 在 monorepo 中"共享工具包改动会误 bump 无关包"的风险(pkgpulse 对比)。
  • 安全属性:两阶段可分离(analyze → publish),官方推荐短时 GITHUB_TOKEN。

3.3 release-it

  • 机制@release-it/conventional-changelog 插件包装 conventional-changelog(bump 建议 + changelog 写入)。
  • 自定义插件 README):
    • preset.types[]:type/section/effect(bump/changelog/hidden)三态控制
    • writerOptscommitPartial/headerPartial渲染函数直接自定义(Handlebars 模板已废弃)
    • whatBump / ignoreRecommendedBump / strictSemVer:bump 规则细粒度控制
  • monorepo:非原生(多包需逐包运行或外部编排),不适合作为 monorepo 主发布工具。

3.4 Nx Release

  • 机制:conventional commits 自动版本 + changelog;可选 version plans(文件式,兼容 changeset 风格)。
  • 自定义Configure Changelog Format):
    • renderOptionsauthors / applyUsernameToAuthors / commitReferences / versionTitleDate
    • Customize Conventional Commit Types:可改分组 section 标题
    • Nx 22+ 自定义 ChangelogRenderer:继承基类实现 renderMarkdown完全掌控输出格式
  • 代价:依赖整个 Nx 工具链(nx.json 生态),纯发布场景引入成本高。

四、安全审计(供应链事件)

发布工具是供应链攻击的高价值目标,2025-2026 已发生多起直接攻击事件:

事件时间与发布工具关系
TanStack 事件2025-05changesets + pnpm + OIDC 发布管线被 GitHub Actions 缓存投毒利用,84 个恶意版本带合法 SLSA provenance 发布
S1ngularity 事件2025-08-26Nx 仓库的 GitHub Actions workflow 漏洞被利用,盗取 npm 发布 token,Nx 多个包被推送恶意版本(sonatype-2025-003584)
Shai-Hulud 蠕虫2025-09180+ 包被投毒,窃取凭据并自我复制(含 GitHub Actions workflow 注入)
chalk/debug 事件2025-09维护者凭据钓鱼,主流包更新被注入恶意代码
Axios 事件2026-03axios 1.14.1 / 0.30.4 恶意版本
AsyncAPI / miasma2026-07发布管线被攻破,5 个官方包被推送恶意版本

对发布工具选型的启示(多源确认,SonatypeTanStack postmorteme18e 建议):

  1. OIDC trusted publishing + 最小权限是当前发布管线的标准安全基线(长期 token 是主要被攻击面);
  2. **changesets 两阶段流程(Version PR 分离发布)**在安全性上有结构性优势:publish 必须经过人工合并 Version PR(pkgpulse 对比);
  3. semantic-release 的"全自动即发布"模式在 CI 环境被攻破时没有人工闸门,风险面更大;
  4. 发布 job 不应与构建/依赖安装共享缓存与凭据(TanStack 教训)。

五、对 dependfix 的选型建议

背景

  • 现状:pnpm workspace + changesets 2.31.1,OIDC 发布已落地(发布指南),版本 0.1.0 未发布;
  • 诉求:CHANGELOG.md 采用用户习惯的 conventional-changelog-cmyr 格式(momei 同款);
  • 约束:两包 monorepo(dependfix / @dependfix/core)、Conventional Commits 提交纪律已建立(commitlint + cz-cmyr)。

方案对比

方案说明格式达成度工程成本
A. changesets + 自定义 changelog 模块changelog 指向自定义模块,条目输出 cmyr 风格⚠️ 条目像,标题/分组仍为 changesets 默认
B. changesets(changelog: false)+ conventional-changelog-cmyr-config 生成版本管理仍用 changesets,changelog 用同一 preset 生成(与 momei 完全同构)✅ 100%中(新增 2 个 devDeps + 生成脚本 + tag 策略配合)
C. 迁移 semantic-release + semantic-release-monorepo全自动 commit 驱动✅ 100%(同生态)高(monorepo 插件配置复杂、误 bump 风险、OIDC 流程重做)
D. 迁移 Nx Release自定义 renderer 完全控制✅ 100%高(引入整个 Nx 工具链)

推荐:方案 B

理由:

  1. 格式 100% 达成conventional-changelog-cmyr-config 正是 momei 格式的生成器,数据源(conventional commit)与项目提交纪律(cz-cmyr)完全匹配;
  2. 保持已落地的发布链路:OIDC 认证、changeset publish 自动 tag、Push release tags 等均不受影响(changelog: false 只影响 changeset version 的 changelog 写入);
  3. 版本管理保留 changesets 的意图驱动优势(人工选择 bump 类型),规避 semantic-release 在 monorepo 的误 bump 风险;
  4. 安全基线不变:两阶段发布(Version PR 人工合并)继续保留。

方案 B 落地要点(待用户确认后实施):

  • .changeset/config.json"changelog": false
  • devDependencies 新增:conventional-changelogconventional-changelog-cmyr-config@^3
  • 新增生成脚本(如 scripts/changelog.mjs):根级 CHANGELOG.md 全仓库生成;包级 CHANGELOG.md 需 gitRawCommitsOpts.path 过滤 + 包级 tag 序列(tagPrefix)
  • tag 策略:compare 链接需要 v*pkg@version tag 序列(changeset publish 已打 pkg@version tag;根级可用 v* 补打)
  • 0.1.0 首版:从现有 git 历史真实生成(非手写)

六、来源清单

数据时效说明:GitHub stars/活跃度为 2026-08-02 实时抓取;周下载量为 2026-02 第三方数据;安全事件均附官方/安全厂商一手来源。

Released under the MIT License.