☰
conventional-changelog-writer 版本演进全解析:从 v1 到 v9 的架构变迁与配置项深度指南
2026/9/25 3:47:30 网站建设 项目流程
  • 开发工具
  • CLI
  • 文档

【免费下载链接】conventional-changelog

Generate changelogs and release notes from a project's commit messages and metadata.

项目地址:https://gitcode.com/gh_mirrors/co/conventional-changelog
点击查看免费下载

本文以 packages/conventional-changelog-writer/CHANGELOG.md 为主线,结合conventional-changelog-writer包的源码(writers.ts、options.ts、commit.ts、context.ts 等),系统梳理该包从独立仓库时期(v1.x,2016 年)到 monorepo 化(v2.0.0,2017 年),再到 TypeScript 重写(v8.0.0,2024 年)与渲染函数替换(v9.0.0,2026 年)的完整演进史,并逐项讲解当前版本的 API、CLI 用法与全部配置项。

一、包定位:conventional-changelog-writer 在工具链中的角色

conventional-changelog-writer是 conventional-changelog 生态中负责"把结构化 commit 数据渲染成 Markdown 变更日志"的核心渲染层。它的上游是conventional-commits-parser(把原始 commit message 解析成结构化对象),下游则是直接生成CHANGELOG.md文本。README 对其功能的描述只有一句话——"Write logs based on conventional commits and templates"(基于 Conventional Commits 与模板编写日志),但整个包的能力远不止于此:

  • 提供流式、异步迭代器、整串三种使用形态(见 writers.ts);
  • 内置 commit 分组、排序、日期格式化、revert 过滤、上下文推导等默认逻辑;
  • 支持通过transform、generateOn、template、各 partial 渲染函数实现完全定制化输出;
  • 附带一个可直接消费行分隔 JSON(LDJSON)的 CLI 工具。

二、版本演进主线:从模板字符串到渲染函数

CHANGELOG.md 记录了从 v0.4(2015 年)到 v9.2.1(2026 年)的完整历史。以下是决定架构走向的几个关键节点:

2.1 独立仓库时期(v1.x,2016 年)

  • v1.0.0(2016-02-05):首个正式发布。此前的 v0.x 阶段奠定了核心概念:doFlush、generateOn、notes、transform等选项已具雏形。
  • v1.1.0:generate时把originalCommits作为最后一个参数传入。
  • v1.4.0/v1.4.1:context 在repoUrl存在时自动回退并使用它做引用链接(auto link references)。

2.2 并入 monorepo 与 2.0.0 大重构(2017 年)

v2.0.0 是第一个"里程碑式"破坏性版本,CHANGELOG 中列出的变更揭示了当时的设计决策:

  • context.host不再能改变context.linkReferences的默认值——如果 host 未知,context.host为undefined,所有链接将直接使用context.repository;
  • closes更名为references;notes对象从键值对象改为数组,每个 note 形如{ title: 'BREAKING AMEND', text: 'some breaking change' };
  • options.replacements更名为options.map,且可以接受函数;
  • commitGroupsCompareFn→commitGroupsSort、commitsCompareFn→commitsSort、noteGroupsCompareFn→noteGroupsSort、notesCompareFn→notesSort;
  • version不再是必需字段,移入context对象,若最后一个 commit 中带版本号会覆盖它;
  • 默认排序函数从按字典序改为localeCompare;
  • options.hashLength、options.maxSubjectLength、options.map被废弃,统一收进options.transform;
  • context暴露finalizeContext,允许在最后阶段修改 context。

2.3 统一版本节奏期(v3-v7,2018-2023 年)

  • v3.0.0(2018-01-29):重构 release 标题生成逻辑,所有标题层级统一为##(h2),patch 版本标题用<small>包裹以保持视觉层级,目的是更好地兼容屏幕阅读器与 Markdown 解析器(对应 issue #214)。
  • v4.0.0(2018-05-29):从 header 模板中移除锚点标签,并明确建议消费者使用版本对应的完整 release 页面 URL(permalink),而非依赖可能不存在的锚点。
  • v5.0.0(2020-12-30):排序时不再支持嵌套对象属性(nested object properties),并移除compare-func依赖,使排序结果在不同 Node 版本间保持一致。
  • v6.0.0(2023-06-06):要求 Node >= 14,并尽可能从依赖中移除 lodash。
  • v7.0.0(2023-08-26):要求 Node >= 16;使用Intl.DateTimeFormat替代dateformat;统一各 preset 的接口(preset 均导出配置工厂函数);transform异步处理器得到修复。

2.4 TypeScript 重写与 ESM 化(v8.0.0,2024 年)

v8.0.0 是近年来影响最大的一次破坏性发布:

  • 重写为 TypeScript(PR #1150),conventional-changelog-writer与conventional-commits-filter(PR #1178)同步 TS 化;
  • 除gulp-conventional-changelog外,所有包均为 ESM-only(PR #1144,从 CommonJS 迁移);
  • 要求Node >= 18;
  • 新增formatDate选项(PR #1189,关闭 issue #1186)与timeZone选项(PR #1162);
  • 修复了 Date 对象防修改逻辑(PR #1285):preventModifications的 Proxy 在 getter 中遇到Date实例时直接返回原值,避免把 Date 包进不可变代理导致格式化失败(见 commit.ts);
  • 8.1.0 起,transformCommit方法与相关 utils 被加入导出(PR #1350);
  • 8.2.0 新增skip选项,可在写 changelog 时跳过指定 commit(PR #1346,关闭 issue #1179 与 #342);
  • 8.3.0 统一各 preset 的换行格式,并从simple-libs引入工具函数;
  • 8.4.0 把 hbs 模板内联为代码字符串。

2.5 v9.0.0:渲染函数取代 Handlebars(2026 年)

v9.0.0 是当前最新的大版本,两项破坏性变更直接重塑了定制方式:

  1. Handlebars 模板字符串与 partial 文件被替换为渲染函数(render functions)(PR #1477):template、headerPartial、commitPartial、footerPartial、preamblePartial不再是 hbs 字符串,而是接收 context 并返回字符串(或 Promise )的函数,见 types/options.ts 中TemplateFunction的定义。
  2. 要求 Node.js 22 或更新版本(PR de5e136)。

v9.1.0 支持 changelog 前言的 partial(preamblePartial,PR #1491);v9.2.0 把 CLI 参数解析从meow换成argue-cli(PR #1505);v9.2.1 修复了 host URL 路径拼接问题(PR #1534,关闭 issue #986)。

三、当前版本 API:三种调用形态

conventional-changelog-writer对外暴露三种写入方式(实现于 writers.ts):

3.1writeChangelogString:最直接的整串输出

README 给出的最小示例即此形态。输入是conventional-commits-parser解析后的 commit 数组,输出是完整 changelog 字符串:

import { writeChangelogString } from 'conventional-changelog-writer' // commits parsed by conventional-commits-parser const commits = [/* ... */] const context = { version: '1.0.0', host: 'https://github.com', owner: 'conventional-changelog', repository: 'conventional-changelog' } console.log(await writeChangelogString(commits, context)) /* ## 1.0.0 (2015-05-29) ### Features * **ng-list:** Allow custom separator ([13f3160](https://github.com/...)) ... */

其实现(writers.ts)只是对异步迭代器形态做拼接累加,底层仍是writeChangelog。

3.2writeChangelog:异步生成器(async generator)

返回一个(commits) => AsyncGenerator<string>函数,逐个 yield 每个版本区块的 changelog 文本。第三个参数includeDetails为true时,yield 的不再是纯字符串,而是Details<Commit>对象:

export interface Details<Commit extends CommitKnownProps = CommitKnownProps> { log: string keyCommit: Commit | null }

(见 types/index.ts)——log是渲染结果,keyCommit是触发本区块生成的"关键 commit"(通常是携带版本号的提交)。

3.3writeChangelogStream:Transform 流

Transform.from(writeChangelog(...))一行代码把生成器包装成 Node.js Transform 流(writers.ts),便于与pipeline、stdin/stdout等流式场景组合。

3.4 核心工作流

从 writers.ts 的生成器实现可以还原完整处理流水线:

  1. getFinalOptions(options)合并默认选项(见下节),getFinalContext(context, finalOptions)推导最终 context;
  2. 对每个 commit 调用transformCommit(chunk, transform, finalContext, finalOptions)——先经preventModifications包裹为不可变代理,再交给 transform 函数,返回值(patch)与原始 commit 合并,并把raw指向原始 commit(commit.ts);
  3. 若skip?.(keyCommit)返回 true,则跳过该 commit;
  4. generateOn(keyCommit, commitsGroup)判定是否该生成一个 changelog 区块;默认实现是"commit.version 是合法 semver 时生成"(见 options.ts);
  5. 命中的 commit 累积到commitsGroup,由createTemplateRenderer渲染出文本块,最终按doFlush/reverse语义决定是否 yield。

注意reverse语义:正常顺序是"时间倒序"(最新在前),reverse: true则按时间正序处理——对应 types 注释"normal order means reverse chronological order"。

四、配置项全解析(Options Reference)

当前版本的完整配置项定义在 types/options.ts,默认值在getFinalOptions(options.ts)中集中给出。下表是全部可配置项:

配置项类型默认值说明
groupBykeyof Commit'type'按哪个字段对 commit 分组;设为 falsy 则不分组
commitsSort字段名 | 字段名数组 | 比较函数'header'commit 组内排序;falsy 则不排序
commitGroupsSort同上无分组之间的排序
notesSort同上'text'note 的排序
noteGroupsSort同上'title'note 分组的排序
ignoreRevertedbooleantrue是否忽略被 revert 的 commit(借助conventional-commits-filter的filterRevertedCommitsSync,见 context.ts)
reversebooleanfalsetrue 时按时间正序(chronological)处理
doFlushbooleantrue是否把最后一段(可能为空的)commit 冲刷输出;从 v0.5.0 引入
transform函数defaultCommitTransform变换 commit,返回 patch 对象与原始 commit 合并;返回 falsy 值则该 commit 被忽略
generateOn函数 | 字段名 |nullcommit => Boolean(semverValid(commit.version))判定何时生成 changelog 区块;字符串形式表示"该字段存在即生成",非函数非字符串则永不生成(见 options.ts)
template渲染函数内置 template把准备好的 context 渲染成文本(v9 起为函数而非 hbs 字符串)
headerPartial渲染函数内置渲染 release 标题
preamblePartial渲染函数内置渲染 release 标题之后的引言文本(v9.1.0 新增支持)
commitPartial渲染函数内置渲染单条 commit 条目
footerPartial渲染函数内置渲染 release 底部 notes
finalizeContext函数恒等函数渲染前最后一次修改 context 的机会,接收(context, options, filteredCommits, keyCommit, commits)
debug(message) => voidnoop输出调试信息,默认会打印最终 context(Your final context is: ...,见 context.ts)
formatDate(date) => stringyyyy-mm-dd格式v8.0.0 新增;默认实现取toISOString().slice(0, 10)(见 utils.ts)
skip(commit) => boolean无v8.2.0 新增;返回 true 则跳过该 commit 的写入

几个容易忽略的实现细节:

  • 排序统一走createComparator:字符串字段名会被编译成(a[key] || '').localeCompare(b[key] || ''),字段名数组则逐字段拼接后比较,也可直接传自定义比较函数(utils.ts)。这正是 v5.0.0 起"不再支持嵌套对象属性"的原因。
  • 默认 transform 的裁剪行为:defaultCommitTransform会把 hash 截断为前 7 位、header 截断为前 100 个字符,并用formatDate格式化committerDate(注意用的是 committerDate 而非 authorDate,这一约定自 v2.0.0 起确立),见 options.ts。
  • linkReferences 的自动推导:只要linkReferences不是显式 boolean、且同时存在repository/repoUrl与commit/issue,就会自动置为 true(context.ts),这是 v0.4.1/v1.4.x 时期"linkReferences 与 host 无关"这一破坏性变更的延续。
  • isPatch推断:若 context.version 是合法 semver,会据此推导isPatch(semver.patch(version) !== 0),见 context.ts。
  • 版本号非必需:version不是必需字段(v2.0.0 起移入 context),若 keyCommit 上带版本号会覆盖 context 中的版本——这与generateOn的默认 semver 判定共同支撑"一个 commit 对应一个 release 区块"的模型。

五、CLI 使用指南

包内自带 CLI 入口(src/cli/index.ts),可直接消费行分隔 JSON 文件或 stdin:

Usage conventional-changelog-writer <path> [<path> ...] cat <path> | conventional-changelog-writer Example conventional-changelog-writer commits.ldjson cat commits.ldjson | conventional-changelog-writer Options -c, --context A filepath of a json that is used to define template variables -o, --options A filepath of a javascript object that is used to define options

参数解析由argue-cli完成(v9.2.0 起替换原meow):

  • -c, --context:指向一个 JSON 文件,内容作为模板变量(context);
  • -o, --options:指向一个 JavaScript 对象文件(.json或可导入的模块,loadDataFile依据扩展名决定JSON.parse还是动态import,见 cli/utils.ts);
  • 位置参数为 commit 文件列表,每个文件按JSON.parse解析(单条 commit 对象);若未提供且 stdin 非 TTY,则从 stdin 按 LDJSON 流式读取(parseJsonStream)。

内部实现通过pipeline(inputStream, writeChangelog(context, options), process.stdout)把解析流、生成器与 stdout 串起来,任何错误都会打印并process.exit(1)。测试夹具中的 commits.ldjson 与 context.json 可直接作为 CLI 输入的参考样例。

六、配套测试与验证

包的测试覆盖了以上全部行为,可在仓库中直接查阅:

  • writers.spec.ts:验证三种 API 的输出、includeDetails、doFlush、reverse等生成语义;
  • commit.spec.ts:验证 transform 的异步处理、falsy 返回值忽略 commit、不可变代理(包括 Date 特殊处理)等;
  • context.spec.ts 与 options.spec.ts(见 utils.spec.ts):验证分组、排序、日期格式化、比较器编译;
  • template.spec.ts:验证渲染函数模板与 partial 的组合;
  • CLI 相关测试见 cli/index.spec.ts。

七、迁移要点与实战建议

针对 CHANGELOG 中列出的各破坏性变更,升级到 v9 时需注意:

  1. Node 版本:v9 要求 Node >= 22,v8 要求 Node >= 18,v7 要求 Node >= 16,按需选择匹配版本;
  2. ESM-only:v8 起包只能通过import使用,CommonJS 项目需改用动态import()或升级构建;
  3. 模板改写:v9 起把 hbs 字符串模板(含 partial 文件)改写为渲染函数——这是迁移工作量最大的部分,函数签名均为(context) => string | Promise<string>;
  4. 排序与选项名:v5 起排序不再支持嵌套属性、按localeCompare比较;v2 起的commitsSort/commitGroupsSort/notesSort/noteGroupsSort命名沿用至今,不要使用旧的*CompareFn命名;
  5. 定制入口收敛:hashLength/maxSubjectLength/map等旧选项早已废弃,统一在transform内实现;需要按 commit 粒度过滤请用skip(v8.2.0+),需要整体跳过 revert 提交请保持ignoreReverted: true。

从 v0.4 到 v9.2.1 的十年演进中,conventional-changelog-writer经历了"模板字符串 → 内联 hbs → 渲染函数"的模板机制迭代、"CJS → ESM"的模块体系迁移、"JS → TypeScript"的类型化改造,以及依赖面的持续瘦身(移除 lodash、compare-func、meow)。理解这份 CHANGELOG,等于同时掌握了该包全部配置项的来历、默认值与最佳实践。

  • 开发工具
  • CLI
  • 文档

【免费下载链接】conventional-changelog

Generate changelogs and release notes from a project's commit messages and metadata.

项目地址:https://gitcode.com/gh_mirrors/co/conventional-changelog
点击查看免费下载
上一篇:如何优化Doom3.gpl的内存管理与资源加载?开发者必看的终极指南
下一篇:Whisper.cpp终极指南:高性能离线语音识别的颠覆性解决方案

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询