Expo 根级 CHANGELOG 深度解读:SDK 版本节奏、变更分类体系与发布工程流水线
本仓库根目录的 CHANGELOG.md 是 Expo 客户端面向开发者的官方变更记录:它只收录随 SDK 一同发布的、需要用户知晓的变更,而不像多数项目那样记录每一笔提交。读完本文,你可以掌握 Expo SDK 的版本节奏(47 → 57 的发布时间表)、五级变更分类体系如何驱动 SemVer 版本号递增,并了解发布工程背后的自动化工具链——et merge-changelogs 如何把 packages 下数百个包的变更汇总进根 CHANGELOG,以及代码评审机器人如何自动补全条目链接。
一、文档定位:两级 Changelog 体系与 Unpublished 区
CHANGELOG.md 开头的原文说明了两条核心规则(见 CHANGELOG.md):
- 这是 Expo client 的开发者可见变更记录;
- 只有在某个 SDK 中发布的包级变更才会汇总到这里;未随 SDK 发布的包级变更,要等到发布前才追加进本文件,在此之前应查看 packages 目录中各包自己的 CHANGELOG。
由此形成两级体系:
- 包级 changelog:
packages/expo-camera/CHANGELOG.md等每个包各自维护,贡献者每次改动包时同步更新; - 根级 CHANGELOG:只在 SDK 发布时由工具链合并生成,代表一次“SDK 快照”。
文件顶部常驻一个 ## Unpublished 区块(CHANGELOG.md#L6-L14),其中预置了三个空分类标题(### 📚 3rd party library updates、### 🛠 Breaking changes、### 🎉 New features、### 🐛 Bug fixes),作为 SDK 发布前变更条目的暂存区。从源码 tools/src/Changelogs.ts#L87-L90 可以看到这一约定被固化为常量:
UNPUBLISHED_VERSION_NAME = 'Unpublished':未发布版本标题;VERSION_EMPTY_PARAGRAPH_TEXT:当某版本没有用户可见变更时写入的占位说明。
解析规则在 tools/src/Changelogs.ts#L92-L100 中定义:二级标题(depth 2)表示一个版本,三级标题(depth 3)表示变更类型,列表项即条目。
二、版本时间线:从 SDK 47 到 SDK 57 的发布节奏
当前仓库 CHANGELOG 覆盖 13 个 SDK 主版本,标题格式统一为 ## <版本> — <发布日期>。按时间倒序整理如下:
| SDK 版本 | 发布日期 | 与上一版间隔 |
|---|---|---|
| 57.0.0 | 2026-07-08 | 约 1 个月 |
| 56.0.0 | 2026-06-01 | 约 3.5 个月 |
| 55.0.0 | 2026-02-25 | 约 6 个月 |
| 54.0.0 | 2025-09-10 | 约 5 个月 |
| 53.0.0 | 2025-04-30 | 约 5.5 个月 |
| 52.0.0 | 2024-11-08 | 约 6 个月 |
| 51.0.0 | 2024-05-07 | 约 4.5 个月 |
| 50.0.0 | 2023-12-12 | 约 6 个月 |
| 49.0.0 | 2023-06-27 | 约 4.5 个月 |
| 48.0.0 | 2023-02-09 | 约 4 个月 |
| 47.0.0 | 2022-10-28 | — |
可以看到 Expo SDK 主版本大致保持每季度至半年一次的节奏;SDK 56 与 57 之间间隔明显缩短(2026-06-01 → 2026-07-08),说明 2026 年进入了一个更紧凑的发布周期。每个版本标题后跟随四个固定分类小节,下文第三节详解。
三、变更分类体系:六个标题如何驱动版本号
每个 SDK 版本下使用带 emoji 的三级标题对条目分组。这套分类并非纯展示——正如仓库贡献指南 guides/contributing/Updating Changelogs.md 所述,“把条目放进正确的分类很重要,因为发布脚本会依据分类决定包发布时如何递增版本号”。
分类在源码中是强类型枚举 tools/src/Changelogs.ts#L52-L82(ChangeType),与文档一一对应:
| 分类标题 | 语义 | 版本递增含义 |
|---|---|---|
🛠 Breaking changes |
需要用户改代码或项目配置的 API 变更 | 触发 major 递增 |
🎉 New features |
非破坏性的公开 API 新增;内部新功能应放 Others | 至少 minor 递增 |
🐛 Bug fixes |
缺陷修复、澄清歧义的文档修正 | patch 级别 |
⚠️ Notices |
不兼容但保留向后兼容的弃用声明、边角行为变化 | 需用户知晓,通常 minor/patch |
💡 Others |
内部重构、构建工具、例行工作等 | 不直接影响用户 |
📚 3rd party library updates |
Expo Go 中升级的第三方库(如 react-native-reanimated) |
仅用于根 changelog |
根 CHANGELOG 实际出现了前四类(57.0.0 版本同时包含 Breaking changes、New features、Bug fixes 与 Others,见 CHANGELOG.md#L18、CHANGELOG.md#L29、CHANGELOG.md#L114、CHANGELOG.md#L234)。⚠️ Notices 与 📚 3rd party library updates 在近期版本中按需出现——后者按指南约定“仅用于根 changelog”,用于记录 Expo Go 内第三方库的版本升级。
从源码结构看,发布脚本会读取每个包的 changelog 条目并按最高级别分类计算应发布的版本类型(见 tools/src/publish-packages/helpers.ts#L246-L257:基于包内变更“本应发布为某 ReleaseType”,若在 SDK 分支上发布则降级为 patch 递增)。换言之,分类写错会直接导致版本号升错——这是把条目归类当作强约束的原因。
四、SDK 57.0.0 实例剖析:一次完整 SDK 快照里有什么
以最新发布的 57.0.0(CHANGELOG.md#L16-L279)为例,完整走读一个版本的记录结构。
4.1 破坏性变更(Breaking changes)
57.0.0 列出 4 项,全部需要用户侧配合:
@expo/ui(universal/android):文本输入改用BasicTextField组件,替代 Filled Material TextField——原生 UI 外观会发生可见变化;expo-modules-jsi(iOS):JavaScriptError由“不可拷贝的 struct”改为“遵循Error的可拷贝 class”,且JavaScriptValue不再遵循Error——原生模块作者需迁移 Swift API;expo-font(web):移除Server.resetServerContext(),服务端字体状态改为经AsyncLocalStorage按渲染作用域隔离;@expo/cli:expo prebuild默认清空并重新生成原生目录,需传--no-clean才能应用到已有目录。这是最容易被 CI 脚本踩中的行为变更:升级 CLI 后若构建脚本依赖增量 prebuild,需要显式传参。
4.2 新特性(New features)要点
- 新包首发:
Initial release of @expo/require-utils——每个 SDK 中首次入列的包都会以这种固定句式登记; - CocoaPods Bundler 支持:
pod-install、@expo/package-manager、@expo/cli三处同步支持 Bundler 托管的 CocoaPods 安装(同一 PR 在三包 changelog 中各记一条); - 实验性平台:
expo-modules-autolinking新增实验性tvos/macos解析,@expo/cli中由expriments.outOfTreePlatforms配置门控; @expo/ui批量扩充:iOS 侧新增大量 SwiftUI 修饰符(accessibilityHidden、accessibilityIdentifier、dynamicTypeSize、listRowSpacing、自定义 SF Symbols、strokeBorder等),Jetpack Compose 侧新增NavigationBar/NavigationBarItem、BasicTextField、onGloballyPositioned,web 侧<Host>支持seedColor与colorScheme覆盖;expo-router:新增standard-navigation集成、从expo-router/drawer再导出抽屉内容组件、native-tabs 为disabled标签页发出isPrevented: true的tabPress事件、原生 Stack 选项新增unstable_nativeProps;expo-modules-core(iOS):新增@Record宏(免@Field包装直接由存储属性合成 record)、@Event宏(把函数类型var变成类型化 JS 事件),且@ExpoModule可自动从类名合成模块 JS 名,Name(…)定义项不再必填——这显著降低了原生模块作者的样板代码量;- 面向 JS 的新 API:
Linking.clearInitialURL()重置缓存的深链 URL;expo-media-library的Query支持按isFavorite过滤并新增Query.exeForMetadata()廉价批量拉取;expo-image-picker允许在 iOS 模拟器调用launchCameraAsync;expo-contacts表单新增cancelButtonTitle/showsCancelButton/preventAnimation选项;expo-network与expo-clipboard新增 macOS 平台支持。
4.3 缺陷修复(Bug fixes)
57.0.0 的修复条目按包分组,其中信息量最大的几条:
expo-sqlite:useLibSQL: true在 Android 上的致命 JNI 崩溃——原因是 libSQL 会话绑定在 Kotlin 与默认原生绑定已切到ByteBuffer后仍声明byte[]签名;expo-sensors:预构建的ExpoSensors.xcframework在 iOS 上永远返回 motion 权限denied,根因是 prebuild 配置无条件定义了本应仅在显式motionPermission: false时才设置的EXPO_DISABLE_MOTION_PERMISSION;expo-modules-core(iOS):修复新架构下按r触发的 reload 死锁(reloadAppAsync已在主线程时改为同步触发 reload);修复Updates.reloadAsync()时旧AppContext提前析构导致的崩溃;@expo/ui:数十条覆盖 SwiftUI/Compose 布局、手势、安全区、community/bottom-sheet嵌套滚动等细节;expo(fetch 层):Android 上gzip/br/zstd响应的解压修复、bodyUsed在二次 clone Response 时泄漏、无 body 的POST/PUT/PATCH误发单个0x00字节等。
4.4 Others:内部变更与性能事实
Others 类包含对贡献者重要但对终端用户透明的改动,例如:
expo-modules-jsi(iOS)性能:同步 host function 不再每次调用分配JavaScriptRef,实测 no-op@JShost 调用基线约快 10%;JavaScriptUnownedValue缓存 immortalIRuntime后,addNumbers约快 16%、addStrings约快 24%——CHANGELOG 中明确给出了测量口径,属于可核实的实现事实;@expo/cli:DevTools 插件新增serverEntryPoint(在 CLI 进程中处理 HTTP/WebSocket)与bannerTitle(启动横幅标题);expo-image-picker:包入口切换到 TypeScript 源码、仅输出声明文件。
4.5 对照:SDK 56.0.0 的平台基线抬升
56.0.0(CHANGELOG.md#L280-L389)的 Breaking changes 由约 40 条同构条目构成:几乎所有核心包统一“Bumped minimum iOS/tvOS version to 16.4, macOS to 13.4”(同一 PR 批量修改),外加三项重量级变更——expo-modules-core 用 Swift 编写的 ExpoModulesJSI 包替换了 Objective-C++ JSI 层(第三方原生模块必须迁移)、expo-file-system 的 copy()/move()/write()/readBytes()/writeBytes() 变为异步(同步版本改用 *Sync() 后缀)、以及 expo-media-library/expo-contacts/expo-calendar 将面向对象新 API 提升到根导入、旧 API 迁至 */legacy 入口。升级 56 的项目应在 CI 中验证最低系统版本与同步/异步 API 调用点。
五、发布工程:merge-changelogs 与 changelogVersions.json
根 CHANGELOG 并非手工维护,而是 SDK 发布流程的一部分,相关实现集中在 tools/src:
et merge-changelogs(别名mc):实现见 tools/src/commands/MergeChangelogs.ts。其工作流程为:- 读取根 CHANGELOG.md 与 changelogVersions.json;
- 找到上一个已发布版本,用
semver.inc(previous, 'major')计算下一个 SDK 版本,并预先把下一个版本的包版本映射初始化为上一个版本的拷贝(MergeChangelogs.ts#L44-L53); - 遍历所有非 private、且在
changelogVersions.json中未被显式置null的包,收集“自上一 SDK 中捆绑版本之后”的全部条目(MergeChangelogs.ts#L57-L64); - 未曾在上一 SDK 出现的包会被询问是否做首发(initial release),确认后以
Initial release of <包名> 🥳句式插入 New features 区(MergeChangelogs.ts#L126-L150)——这正是 57.0.0 中@expo/require-utils条目的来源; - 支持
--cut-off选项在合并后截断根 changelog。
changelogVersions.json:记录“每个 SDK 版本捆绑了哪些包的哪个版本”的快照矩阵。例如 57.0.0 下expo-camera为57.0.1、@expo/cli为57.0.6、expo-modules-core为57.0.3、expo-router为57.0.4(changelogVersions.json#L2-L102);置null表示该包未捆绑进 SDK(如expo-dev-client)。该文件同时是“自上一 SDK 以来收集哪些条目”的基准:合并时按上一版本记录的包版本号作为fromVersion起点(MergeChangelogs.ts#L113-L114)。- canary 发布:SDK 版本化的包在
main分支上 canary 时递增到下一 major(如55.0.2 → 56.0.0),在sdk-*分支上只递增 patch(tools/src/publish-packages/tasks/publishCanary.ts#L239-L240)。
六、条目写作规范与自动化协作
结合 guides/contributing/Updating Changelogs.md 与仓库内实现,一个合格条目需满足:
- 描述性强、简洁:让零上下文的读者也能看懂改动;
- 位于
Unpublished区正确分类下; - 包含 PR 与作者链接,格式固定为
(#NNNNN by @author); - 只允许纯文本与链接:列表、表格、引用块、图片等 Markdown 元素一概不允许,迁移指南应写进 PR 描述或独立文档。
两个自动化环节降低了执行成本:
- 代码评审机器人自动补链接:tools/src/code-review/reviewers/reviewChangelogEntries.ts 扫描 PR diff 中除根目录外所有
CHANGELOG.md的新增列表项,用正则解析其中的 PR 链接(tools/src/Changelogs.ts#L114-L120 的textToChangelogEntry),若缺少 PR 链接则以 GitHub suggestion 块形式贴出(... by @author)补全建议,贡献者一键 apply 即可;仓库中还存在checkMissingChangelogs评审器(tools/src/code-review/reviewers/checkMissingChangelogs.ts)用于提醒缺失的 changelog。 et add-changelog:交互式命令,按包名、PR 号、作者、条目文本与类型(bug-fix/new-feature/breaking-change/library-upgrade/notice/other)生成规范条目,实现见 tools/src/commands/AddChangelog.ts#L88-L95。
七、如何阅读这份 CHANGELOG
- 升级 SDK 前:定位目标版本的
### 🛠 Breaking changes小节,逐条确认是否有命中你 API 面的条目(如 57 的expo prebuild --no-clean、expo-file-system异步化在 56 的同类变更); - 排查“升级后行为变了”:先查对应版本的 Bug fixes 与 Others 小节,条目自带 PR 号可直接溯源提交;
- 确认某 SDK 里各包的准确版本:查 changelogVersions.json 中对应 SDK 键下的映射,而不是只看根 CHANGELOG;
- 关注下一 SDK 的动向:看
## Unpublished区——当前该区块为空,说明最近的变更都已归入 57.0.0。
这份根级 CHANGELOG 因此不仅是历史流水账,而是 Expo 发布契约的一部分:分类体系约束版本递增,changelogVersions.json 约束包集合快照,et merge-changelogs 与代码评审机器人则保证从包级 changelog 到 SDK 级记录的汇总过程可复现、可审计。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0624
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00