Heroicons 版本演进全解析:从 CHANGELOG 读懂开源图标库的发布历史与工程实践
Heroicons 版本演进全解析:从 CHANGELOG 读懂开源图标库的发布历史与工程实践
CHANGELOG.md 是 Heroicons 项目自 2020 年首个版本以来最权威的变更记录档案,完整记录了从 0.2.0 到 2.2.0 数十个版本的图标新增、视觉修正、包工程化改造与框架适配历程。本文以该文档为核心骨架,结合仓库内的 src/ 图标源码、scripts/ 发布工具链与 react/、vue/ 包的 package.json 配置,系统梳理 Heroicons 的版本演进脉络,帮助读者理解其版本管理规范、图标集合变迁规律,以及如何在升级依赖时准确评估各版本带来的行为变化。
版本记录的规范基础:Keep a Changelog 与 SemVer
CHANGELOG 开篇即声明了两条约束项目版本记录方式的规范:
- 格式基于 Keep a Changelog:所有变更被归类为
Added(新增)、Changed(变更)、Fixed(修复)等语义化分组,按时间倒序排列; - 遵循 Semantic Versioning(语义化版本):
MAJOR.MINOR.PATCH三段式版本号,主版本号在破坏性变更(如 v2.0.0 的图标集整体重做)时递增,次版本号在新增功能(新增图标、新增框架支持)时递增,修订号用于向后兼容的缺陷修复。
此外,文档在每个版本标题下标注了发布日期(如 ## <a href="https://link.gitcode.com/i/9f5c54e6b279eaebb713b8cef15aa841" target="_blank">2.2.0] - 2024-11-18),并在文件末尾维护了一组版本对比链接,将每个历史版本与其前一版本锚定,形成可追溯的发布时间线。当前仓库根目录 [package.json 中 version: "2.2.0" 与 CHANGELOG 最新的已发布版本保持一致,而 [Unreleased] 区块则预留了尚未发布的变更位置(当前为空)。
2.x 时代:全新图标集与工程化打磨
Heroicons 2.0 是项目历史上最重要的一次版本跃迁(2022-08-23),CHANGELOG 将其描述为 "Completely new icon set",即图标集整体重做。此后 2.x 系列经历了从"补全图标"到"打磨视觉细节"再到"工程化改造"三个阶段,本文按主题归类梳理。
图标集扩充时间线:从补齐到新增
2.x 系列的图标数量经历了多轮扩充,CHANGELOG 中可归纳出以下关键批次:
| 版本 | 日期 | 新增内容 | 可验证的仓库位置 |
|---|---|---|---|
| 2.0.3 | 2022-08-24 | 补齐 v1 缺失的 bars-arrow-down、bars-arrow-up、chevron-up-down、rss |
src/24/outline |
| 2.0.9 | 2022-08-30 | arrow-small-*、battery-*、cube-transparent、currency-bangladeshi、minus-small、plus-small、variable、wallet、arrow-path-rounded-square 等 15 个 |
src/20/solid、src/24/solid |
| 2.0.11 | 2022-09-12 | bug-ant、eye-dropper、pause-circle、play-circle、power、rocket-launch、square-2-stack-3d、stop-circle、trophy、tv、viewfinder-circle、window 共 12 个 |
src/24/outline |
| 2.1.0 | 2023-12-18 | 新增 micro 图标集(16×16 solid),并重建部分图标以提升清晰度 | src/16/solid |
| 2.1.5 | 2024-07-10 | arrow-turn-* 系列、bold、calendar-date-range、divide、document-currency-*、equals、h1/h2/h3、italic、link-slash、numbered-list、percent-badge、slash、strikethrough、underline 共 17 个 |
src/24/outline |
值得注意的是 2.1.0 引入了第四个图标集合:此前的 24×24 outline、24×24 solid、20×20 solid 之外,新增了面向紧凑界面场景的 micro(16×16 solid)集合。从 scripts/verify-names.js 的源码可以看到,仓库内部将四套图标分别命名为 micro(16/solid)、mini(20/solid)、solid(24/solid)、outline(24/outline),npm run lint 会遍历四个集合并交叉比对文件名,确保同一图标名在四个集合中保持一致,这正是 CHANGELOG 中 2.0.3 "补齐缺失图标" 的自动化保障机制。
视觉细节修复:光学对齐与尺寸打磨
2.x 的 Fixed 条目中占比最高的是图标的光学对齐(optical alignment)与尺寸修正,这是手绘图标库区别于程序化生成图标库的核心质量工作:
- 2.0.4:移除 outline 图标
bars-arrow-down、bars-arrow-up、chevron-up-down、rss上多余的描边; - 2.0.5:将
check-*系列图标的弯曲对勾设计改为直线对勾("Modify the curved design ... to a straight check"); - 2.0.6:修正
chevron-*系列、funnel、minus、plus等常用图标的尺寸; - 2.0.7 / 2.0.8:集中修正
hand-thumb-up、hand-thumb-down、plus、minus、heart、tag、check以及arrow-down-*/arrow-up-*系列的光学对齐与尺寸; - 2.0.10:修正
arrow-path的旋转方向,并修复exclamation-triangle的光学对齐; - 2.0.12 / 2.0.13:继续修复
information-circle、minus的对齐问题; - 2.1.1:修复 micro(mini)集合中 chevron 图标的问题;
- 2.2.0:移除
solid/arrow-left-circle中不必要的裁剪路径(clipping path)。
这些逐图标级别的修正解释了为何仓库中存在 src/(原始设计稿)与 optimized/(SVGO 优化产物)两套目录:原始 SVG 经 svgo.24.outline.mjs、svgo.20.solid.mjs 等配置文件驱动 SVGO 压缩后输出到 optimized/,再复制为发布产物。修改图标设计必须同步回到 src/ 源头,这也是 README 中"只接受修复 bug 类贡献(如图标以 fill 而非 stroke 导出)"的工程背景。
包工程化改造:tree-shaking、类型与导出
2.x 中后期,CHANGELOG 的 Fixed 条目从图标视觉转向了 npm 包本身的工程品质,这一系列改造直接影响所有下游使用者的打包产物:
- 2.0.14:指定显式 package exports("Specify explicit package exports"),同时在 react/package.json 中可以完整看到这套
exports映射——为16/solid、20/solid、24/outline、24/solid每个入口都声明了import(ESM)、require(CJS)与types(.d.ts)三种解析目标,并支持esm/*子路径; - 2.0.15:修复图标 tree-shaking("Fix icon tree-shaking")——这是"按需引入、摇树优化"能力的关键修复,配合 react/package.json 与 vue/package.json 中的
"sideEffects": false声明,让打包器可以安全删除未使用的图标模块; - 2.0.16:添加根级导入(root-level import),其动机记录在 react/index.js 源码注释中:这是为了满足 Vite 的
optimizeDeps功能对根级导入的解析要求,该文件本身是一个 Proxy,一旦被真正访问就会抛出错误,提示用户改从@heroicons/react/16/solid等子路径导入; - 2.0.17 / 2.0.18:修复 React 图标类型声明与
esm路径映射; - 2.1.2:发布包中纳入 LICENSE 文件(仓库内 react/LICENSE 与 vue/LICENSE);
- 2.1.4:进一步提升 React 包的 tree-shakability;
- 2.2.0:新增 React 19 支持,react/package.json 中的
peerDependencies声明为"react": ">= 16 || ^19.0.0-rc",同时兼容 16+ 与 19 版本。
兼容性与升级提示:v1 路径守卫
2.0.1 引入了一个值得注意的兼容性设计:当用户仍从 v1 的导入路径(如 @heroicons/react/outline/xxx)引入图标时,包会主动抛出警告。仓库中 react/outline/index.js 就是这一机制的实现:它是一个 Proxy 对象,任何属性访问都会抛出 "You're trying to import ... from Heroicons v1 but have installed Heroicons v2" 的错误提示,引导用户安装 @heroicons/react@v1 或改用新的子路径。这解释了为什么 CHANGELOG 2.x 系列没有直接删除旧的路径——而是用运行时错误做显式引导,避免静默失效。
1.x 时代:React / Vue 组件化的奠基
1.x 版本记录展示了 Heroicons 从纯 SVG 文件库演进为框架组件库的关键历程:
| 版本 | 日期 | 关键变更 |
|---|---|---|
| 1.0.0 | 2021-03-29 | 首个 1.x 稳定版本 |
| 1.0.1 | 2021-04-14 | 新增 arrow-sm-up、arrow-sm-right、arrow-sm-down、arrow-sm-left 小箭头图标 |
| 1.0.3 | 2021-07-26 | 新增 Vue 类型声明 |
| 1.0.4 | 2021-08-17 | 修复 Vue 类型声明 |
| 1.0.5 | 2021-10-22 | 为 package.json 添加 MIT license、为 SVG 添加 aria-hidden="true" 属性、修复 solid arrows-expand 填充色、为 esm 子包添加 "type": "module" |
| 1.0.6 | 2022-03-02 | React 组件支持 forwardRef、为 package.json 添加 sideEffects、修复文件夹图标、修复 Vue TypeScript 声明、将 stroke-width 从 path 上移到 svg 元素 |
其中 1.0.5 的 aria-hidden="true" 是图标可访问性的基础实践——装饰性图标不应被屏幕阅读器朗读;而 1.0.6 的 forwardRef 支持则让图标组件可以被父组件持有 ref,是组件库满足复杂交互场景的必要能力。stroke-width 从 path 移到 svg 的调整意味着描边宽度成为整个图标的公共属性,下游可通过 CSS 统一覆盖。
0.x 时代:起点与组件化探索
CHANGELOG 对早期版本记录较少但意义明确:
- 0.2.0(2020-05-18):"Everything!"——项目初始图标集诞生;
- 0.3.0(2020-06-01):新增 22 个图标(
fire、shopping-bag、thumb-up、thumb-down、hand、arrows-expand、view-grid、puzzle、folder-download、folder-add、folder-remove等),并首次添加 React 与 Vue 组件,即react/与vue/两个子包的起点; - 0.4.0(2020-08-25):安装时不再运行构建脚本("Don't run build scripts on install")——这是 npm 包发布卫生的重要修正,避免消费者在
npm install阶段触发构建。
0.3.0 中部分图标名(如 thumb-up、view-grid)与 2.x 的命名(hand-thumb-up、squares-2x2)不同,这正是 2.0.0 重做时统一命名规范的佐证。
发布流程的自动化支撑
CHANGELOG 的编写不是手工孤立的,仓库 scripts/ 目录提供了与版本发布配套的工具链,反过来印证了 CHANGELOG 的机器可读性:
- scripts/release-notes.js:给定版本号(命令行参数或 npm 环境变量),用正则
## \[version\] - (.*)\n\n(...)从 CHANGELOG.md 中提取对应版本的变更内容,用于预填 GitHub Release 的发布说明。正则要求每个版本条目必须以## [x.y.z] - 日期开头并以##或[结束,这正是 CHANGELOG 需要保持严格格式的原因; - scripts/release-channel.js:解析版本号判断 npm 发布通道——普通版本(如
1.2.3)输出latest,预发布版本(如4.1.0-alpha.4、0.0.0-insiders.ffaa88)输出对应的alpha、insiders等通道名; - scripts/verify-names.js:作为
npm run lint执行,交叉比对四套图标集合的文件名,保证同名图标在所有集合中同步存在(micro 集合允许通过 scripts/deprecated.js 中登记的deprecated列表豁免缺失)。
发布管线在根目录 package.json 中定义为:prebuild 清理产物目录 → 依次用 SVGO 构建四套优化 SVG → build-react / build-vue 生成框架组件 → prepublishOnly 触发完整构建后发布。这一链条说明 CHANGELOG 中每个"新增图标"条目背后,都对应着 src/ 设计源文件的同步提交与 verify-names.js 的集合一致性校验。
版本与仓库结构的对应关系
将 CHANGELOG 与当前仓库目录树对照,可以建立清晰的"版本 → 目录 → 包"映射:
| 图标集合 | 引入版本 | 原始设计源 | 发布产物(optimized) | npm 导入路径 |
|---|---|---|---|---|
| 24×24 outline | 1.0.0(重做于 2.0.0) | src/24/outline | optimized/24/outline | @heroicons/react/24/outline |
| 24×24 solid | 1.0.0(重做于 2.0.0) | src/24/solid | optimized/24/solid | @heroicons/react/24/solid |
| 20×20 solid(mini) | 2.0.0 | src/20/solid | optimized/20/solid | @heroicons/react/20/solid |
| 16×16 solid(micro) | 2.1.0 | src/16/solid | optimized/16/solid | @heroicons/react/16/solid |
React 与 Vue 两套包的导入路径结构完全一致(参见 react/package.json 与 vue/package.json),组件命名统一采用上驼峰并以后缀 Icon 结尾(如 BeakerIcon),具体用法可参考 README.md 中的 React 与 Vue 示例。
升级决策参考:各版本影响面小结
结合 CHANGELOG 全量记录,可以给出面向实际升级场景的判断依据:
- 从 1.x 升级到 2.x:破坏性变更,图标集整体重做、命名体系改变(如
arrow-sm-up→arrow-small-up)、组件导入路径改变(v1 路径在 2.0.1 起会抛出运行时错误);升级前应检索代码中的旧导入路径; - 2.0.x → 2.1.x:向后兼容,主要收益是新增 micro 16×16 集合(2.1.0)与 17 个新图标(2.1.5),无破坏性变更;
- 2.1.x → 2.2.0:向后兼容,主要收益是 React 19 官方支持(react/package.json 的 peerDependencies 已包含
^19.0.0-rc)与arrow-left-circle裁剪路径的清理; - 若项目使用打包器做按需引入,建议至少处于 2.0.15+(tree-shaking 修复)与 2.1.4+(tree-shakability 进一步改进)以上版本;
- 若使用 TypeScript + React,2.0.14+ 才具备完整的
title/titleId类型与显式 exports 映射。
如需追踪每个版本之间的具体差异,可对照 CHANGELOG.md 底部的版本对比锚点(如 [2.2.0]: ... compare/v2.1.5...v2.2.0)查看相邻版本的完整 diff;而 scripts/release-notes.js 则是自动化提取任意版本变更摘要的标准入口,可作为 CI 发布流程的组成部分直接复用。