尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Expo 单仓库公共 API 兼容性审查:导出映射、类型级破坏与 Changelog 版本策略

Expo 单仓库公共 API 兼容性审查:导出映射、类型级破坏与 Changelog 版本策略 Expo 单仓库公共 API 兼容性审查导出映射、类型级破坏与 Changelog 版本策略【免费下载链接】expoAn open-source framework for making universal native apps with React. Expo runs on Android, iOS, and the web.项目地址: https://gitcode.com/GitHub_Trending/ex/expo本文以 Expo 官方代码审查智能体 public-api.md 为核心系统讲解 Expo 单仓库中「公共 API 破坏性变更」的识别标准从exports映射的解析陷阱、在仓库内能编译但会在消费方项目里失败的类型级破坏到peerDependencies收窄与sideEffects修剪并结合发布工具 tools/src/publish-packages/helpers.ts 与 tools/src/Changelogs.ts 的源码说明 Changelog 标题如何机械地决定 npm 包的 MAJOR/MINOR/PATCH 版本。读完后你能掌握一套可落地的公共 API 兼容性审查清单以及 Expo 发布链路的底层原理。为什么 Expo 需要专门的公共 API 审查Expo 是一个包含约 140 个独立版本化包的单仓库packages/下的每个包都以自己的版本号单独发布到 npm。任何一个导出符号的变更本质上是变更了成千上万个应用依赖的契约。而apps/下的 14 个应用与tools/均标记为private: true从不发布因此 API 兼容性规则不适用于它们——审查范围严格限定在会发布到 npm 的包上。该审查规则定义了整份指南最重要的约束本仓库自己的构建和测试检测不出你所要发现的绝大多数问题。类型级破坏在单仓库内部往往源码兼容只在消费方的项目里失败。因此「CI 是绿的」永远不能作为变更安全的结论。这份规则位于 AI 代码审查系统.expo-agents/code-review/中config.jsonc 约定「agents/目录下的每个 markdown 文件即一位审查员」coordinator.md 负责汇总去重并做最终裁决。public-api 审查员只判断标题与措辞不重复机械检查已经覆盖的事项——这一分工在后面会反复出现。有两个仓库事实塑造了审查工作值得单独强调getMinReleaseType只在 Changelog 的Unpublished区块下存在精确标题 Breaking changes的条目时才选择 MAJOR 升版。把破坏性变更写进 Bug fixes小节就会以 minor 或 patch 版本悄悄发布。标题是承重结构不是装饰。Metro 自 0.82 起默认启用package.json的exports解析而 Expo 仓库运行在较新的 Metro React Native 之上审查指南标注为 Metro 0.84.4 React Native 0.86具体版本以当前分支实际依赖为准。这意味着编辑exports字段现在影响的是应用打包而不只是 Node 的模块解析。Changelog 标题驱动版本源码级证据先看版本决策的代码。helpers.ts 中的getMinReleaseType逻辑非常直白export function getMinReleaseType(changelogChanges: any): ReleaseType { const unpublishedChanges changelogChanges?.versions[Changelogs.UNPUBLISHED_VERSION_NAME]; const hasBreakingChanges unpublishedChanges?.[Changelogs.ChangeType.BREAKING_CHANGES]?.length; const hasNewFeatures unpublishedChanges?.[Changelogs.ChangeType.NEW_FEATURES]?.length; // For breaking changes and new features we follow semver. if (hasBreakingChanges) { return ReleaseType.MAJOR; } if (hasNewFeatures) { return ReleaseType.MINOR; } return ReleaseType.PATCH; }它只读取Unpublished版本区块并按精确字符串匹配小节标题。这些标题定义在 Changelogs.ts 的ChangeType枚举中export enum ChangeType { LIBRARY_UPGRADES 3rd party library updates, BREAKING_CHANGES Breaking changes, // 唯一能触发 MAJOR 的标题 NEW_FEATURES New features, // 触发 MINOR BUG_FIXES Bug fixes, NOTICES ⚠️ Notices, OTHERS Others, }调用点位于 loadRequestedParcels.tsminReleaseType: getMinReleaseType(changelogChanges)。也就是说整个发布工具的升版建议完全由 Changelog 文本中的三级标题决定。真实的 CHANGELOG 可以印证这套结构。以 packages/expo/CHANGELOG.md 为例## Unpublished之下依次是### Breaking changes、### New features、### Bug fixes、### Others每条变更带 PR 号与作者链接例如「Raise minimum Node.js version to^22.13.0(#47202 by kitten)」。还有一个容易忽视的传播机制helpers.ts 的resolveReleaseTypeAndVersion会调用recursivelyAccumulateReleaseTypes沿依赖树递归累积所有依赖包的minReleaseType再用highestReleaseTypeReducer取最高值。换句话说依赖方被判定为 MAJOR会把升版压力传递到当前包此外从 SDK 分支发布时分支名含 SDK 版本即使累积出更高的类型也建议按 patch 处理见 helpers.ts。这两点决定了审查时不能只看单个包还要看它在依赖图中的位置。应标记的破坏性变更一、破坏性变更写在错误的小节下触发条件diff 删除、重命名或改型了某个导出符号把同步 API 改为异步或改变了默认值/返回形状——但对应的Unpublished条目却挂在 Bug fixes、⚠️ Notices或 Others之下。审查时要读的是条目所在的三级标题而不是「是否存在条目」。条目存在本身不够——存在性已由机械检查覆盖只有标题驱动版本升版。这是该审查员职责边界的一个典型体现机械工具管「有没有」人工/模型判断管「挂在哪、说得对不对」。二、exports映射的解析陷阱exports字段的四类问题删除已有 key、把 key 重定向到别的文件、或用更窄的字面 key 替换一个宽泛的模式 key且没有为旧 specifier 保留别名。审查时优先检查包末尾的通配符。以 packages/expo/package.json 为例exports的最后一项是./*: { types: ./*.d.ts, default: ./*.js }它相对包根目录而非build/解析。因此删除一个具名子路径后请求通常会落进这个通配符最终指向一个不存在的文件——错误在消费方解析时才爆发。新增或修改的子路径在已发布形态下无法解析具体形态包括没有default条件default被放在同一对象的其他条件之前条件顺序有意义default之后的内容全部是死代码expo-source条件指向src/但没有build/下对应的构建目标或反之对于带files白名单的包目标路径的顶层段缺失于files数组。packages/expo/package.json 的files白名单就显式列出了build、internal、src、types、virtual等段任何子路径目标若不落在这些段内打包后就会缺失。条件顺序示例。同一文件中.的types条件是这样组织的package.json.: { types: { expo-source: ./src/Expo.ts, default: ./build/Expo.d.ts }, expo-source: ./src/Expo.ts, default: ./build/Expo.js }注意expo-source是自定义解析条件用于单仓库内部的类型解析详见「不应标记」一节default永远排在其后——顺序颠倒会让default之后的条件全部失效。三、在本仓库仍能编译的类型级破坏这是该审查规则中技术密度最高的部分对应四类形态1. 符号从值位置退化为纯类型。export { X }被改成export type { X }导出的enum被替换为类型别名或as const对象加联合类型class被替换为interface。enum 提供值命名空间而联合类型不提供所以EncodingType.UTF8这种取值写法会直接编译失败。此外任何对已有导出 enum 成员初始值的修改也应标记。2. 消费方实现而非调用的类型上的参数加宽/返回收窄。事件监听器与回调签名、hook 的选项回调、config-plugin 的函数类型、消费方需要实现或继承的接口上的方法——参数位置是逆变的按窄参数写的处理器不再满足加宽后的签名。还要区分写法方法语法成员func(x: A): void比属性语法成员func: (x: A) void风险更高属性语法在结构类型下允许放宽方法语法则要求严格匹配审查结论应说明你看到的是哪一种。3. 三种「源码兼容但破坏消费方」的形状。它们在本仓库里不报错却在消费方项目里失败返回类型获得新成员T变成T | undefined或T | null导出结果类型上的属性变为可选导出选项类型上的属性变为必填。4. 泛型类型参数变更。已有类型参数默认值改变、新增无默认值的类型参数、或类型参数约束收紧。修改默认值会静默改变裸引用的含义——不报错类型却变了。5. 子路径迁移。导出从一个入口的 barrel 移除、改加到另一个子路径下——除非原入口保留该标识符并挂deprecatedJSDoc 标签写明新 specifier。消息中指明新路径的抛错桩throwing stub算作迁移路径静默搬家则不算。四、包元数据变更peerDependencies收窄已有 peer 范围的下界提高、||范围中的某个分支被删除、或新增 peer 条目却没有peerDependenciesMeta.name.optional: true——除非同一 PR 还包含一条写明新必需版本的 Breaking changes条目。npm 7 会自动安装 peer 并在依赖树无法解析时报错因此收窄范围会直接变成安装失败。反向的放宽范围永不触发此规则。以 packages/expo/package.json 为参照peerDependencies中expo/dom-webview、react-dom、react-native-web等条目在peerDependenciesMeta中对应{ optional: true }正是这套机制的标准用法。sideEffects修剪sideEffects被设为false或数组中被删掉某个 glob而被删 glob 匹配的文件仍在 import 期做工作全局安装器、polyfill、原型补丁。另外要标记新的 import 期副作用模块——裸import ./Something.fx、全局安装器、polyfill、原型补丁——出现在该数组任何 glob 都匹配不到的路径上。当数组携带成对的src/buildglob 时两个必须同时具备。packages/expo/package.json 展示了成对写法sideEffects: [ *.fx.tsx, *.fx.web.tsx, *.fx.js, *.fx.web.js, ./src/winter/*.ts, ./build/winter/*.js, ./src/async-require/*.ts, ./build/async-require/*.js ]不应标记的情形误报防线审查规则的一半价值在于抑制误报。以下五类明确不标记纯增量表面。选项类型上新增可选属性、新导出符号、新exports子路径、peer 范围放宽、把已有 peer 标记为可选——都不使现有消费方代码失效。同时永远不要要求作者修改包的version字段版本由发布工具负责。包自己实现、消费方只调用的函数上的参数加宽/返回收窄。接受更宽的输入、返回更具体的值对调用方都是向后兼容的。这是整个领域最可能的误报来源报告前必须先确认该签名的角色只有当同一签名同时是消费方实现、作为回调传递或继承的接口的一部分时才升级处理。刻意非公开的入口。./internal/*子路径、src/internal/下的文件、unstable-前缀的子路径、或已带写明替代方案的deprecated标记的符号——它们不携带稳定性承诺不要为其要求破坏性变更条目或 major 升版。packages/expo/package.json 中的./internal/*通配子路径就是这类入口的实例。expo-source条件指向src/的exports条目。这是单仓库类型解析用的自定义条件不是源码泄漏。不要要求把src加进files也不要把files数组中的!src当错误看待。API 变更后重新生成docs/public/static/data/**。文档工作流会自动完成永远不要要求作者手动运行生成器。此外「Changelog 条目缺失」或「条目缺 PR/作者链接」都已被机械检查强制——审查员只判断标题与措辞。结论输出的证据标准规则的最后一条是全篇的收束必须指明哪段消费方代码会被破坏、如何被破坏。如果你说不出具体哪个 import 或调用会停止工作这个发现就不成熟。宁可为零发现也不要给一条投机性的结论。这一标准与 coordinator.md 的汇总规则一脉相承——没有可追踪的失败路径的发现会被直接丢弃与它声称的类别无关。小结审查维度判定要点源码/配置证据Changelog 标题破坏性条目必须挂在Unpublished下的 Breaking changes三级标题下helpers.ts、Changelogs.tsexports 映射删除/重定向/收窄 key 需保留别名条件顺序、default存在性、files白名单一致packages/expo/package.json类型级破坏值位置退化、逆变回调、三种源码兼容形状、泛型默认值以 diff 中的类型声明为准包元数据peer 收窄需 breaking 条目或 optional 标记sideEffects glob 成对packages/expo/package.json误报抑制增量表面、纯被调函数、内部/unstable 入口、expo-source 条件、机械检查项public-api.md对单仓库独立版本化发布的项目而言这套规则的通用启示是把「契约变更」与「机械可查项」分开让工具守住存在性与格式让审查者人或模型聚焦在标题语义、解析顺序与类型角色这三个 CI 盲区上并用「说不出哪段消费方代码会坏就不算发现」作为输出的证据门槛。【免费下载链接】expoAn open-source framework for making universal native apps with React. Expo runs on Android, iOS, and the web.项目地址: https://gitcode.com/GitHub_Trending/ex/expo创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表