插件可以捆绑一个 @wordpress/* 包,同时从 WordPress 加载该包的依赖项。这样,被捆绑的包与其 WordPress 依赖项就可能来自不同的版本。
例如,插件可能捆绑了较新的 @wordpress/dataviews 包,却运行在提供较旧 @wordpress/components 包的 WordPress 版本上。反过来也可能发生:较旧的插件捆绑包可能运行在较新的 WordPress 版本上。
当更改影响到可以单独更新的部分时,请使用本指南,例如:
- 公共或私有 API。
- 包依赖项或入口点。
- 包注册或某种检查(例如允许列表或选择性加入机制),用于决定入口点能否加载。
- 兼容性回退。
如果包及其所有依赖项总是一同发布,则无需使用四版本测试矩阵。但公共 API 更改仍需要进行下文的现有消费者检查。
梳理生产环境中运行的内容
首先记录以下信息:
- 插件或应用程序的捆绑包中包含哪些包。
- 哪些依赖项是从 WordPress 加载的。
- 插件或应用程序支持的最旧 WordPress 版本。
- 仍在维护的插件或应用程序仍在使用的较旧捆绑包版本。
检查每个受影响的入口点。入口点是一条拥有独立构建产物的导入路径,例如主包导入或 /wp 导入。
检查包元数据、构建设置、生成的资源文件以及依赖项提取。依赖项提取决定了捆绑包会将哪些包留给 WordPress 加载。
不要仅依赖包名称或源码导入。它们无法显示生产构建中实际包含的内容。发布新包也不会更新已经部署的捆绑包。
选择要测试的版本
对于旧包,请从更改之前的最后一个发布版本开始。当仍在维护的消费者仍在使用更早的版本时,请将这些版本也纳入测试。
对于 WordPress,请从最旧的受支持版本以及包含所提议更改的版本开始。当中间版本暴露不同的 API 或加载不同的入口点时,请将这些中间版本也加入测试。
如果某个组合超出了支持政策的范围,请明确说明。并记录消费者应改用的包版本、入口点或 WordPress 版本。
测试现有消费者
对于公共 API 更改,请结合候选包使用具有代表性的消费者代码:
- 依据该包已发布的 TypeScript 声明对其进行编译。
- 使用其常规构建设置进行构建。
- 执行已更改的行为。
更新 Gutenberg 仓库内的调用点可以证明新 API 可用,但并不能证明现有消费者仍然可用或拥有迁移路径。
测试四种版本组合
当 WordPress 提供依赖项时,请测试两种混合版本组合:
| 捆绑包 | WordPress 依赖项 | 要确认的内容 |
|---|---|---|
| 旧 | 旧 | 现有行为仍然有效。 |
| 旧 | 新 | 新依赖项仍支持旧捆绑包。 |
| 新 | 旧 | 新捆绑包在每个受支持的 WordPress 版本上都能正常工作。 |
| 新 | 新 | 新代码按预期工作。 |
使用已构建的包进行这些检查。未构建的源码并非消费者所安装的代码。
检查构建
对于每个必需的组合和入口点:
- 在隔离的消费者项目中安装确切的包版本。
- 依据其已发布的 TypeScript 声明进行编译。
- 使用消费者的真实依赖项提取设置进行构建。
- 检查生成的依赖项和导出的 API。
- 在相应的 WordPress 版本中,确认包注册和其他加载检查会选择预期的入口点。
检查行为
在相应的 WordPress 版本上运行受影响的行为。如果更改添加了回退路径,请将其包含在内。
还要检查必须来自同一个包副本的状态。React 上下文、私有 API 锁、注册表和符号都是常见的例子。相同的导出并不会让各个独立的包副本共享相同的状态。
将每个必需的组合记录为 pass、fail 或 unverified。源码测试或 mock 可以显示运行的是哪个分支,但无法重现依赖项提取、独立的包副本或较旧的 WordPress 运行时。
按安全顺序发布更改
两种混合版本组合需要不同的保护措施:
- 新捆绑包搭配旧 WordPress:在使用 API 之前先检查它是否存在,提供回退方案,或者明确提高受支持的最低 WordPress 版本。
- 旧捆绑包搭配新 WordPress:保留旧 API 或兼容路径,直到仍在维护的消费者不再需要它为止。
当新旧 API 可以共存时,请按以下顺序发布:
- 将新 API 添加到由 WordPress 提供的包中。在受支持的捆绑包仍需要旧 API 期间保留它。
- 更新捆绑的包,使其优先使用新 API,并在较旧的 WordPress 版本未提供该 API 时进行回退。
- 防止新代码在回退路径之外使用旧 API。
- 在移除任一兼容路径之前,请先发布所需的 npm 版本和 WordPress 版本。
通过检查 API 是否存在来进行判断,而不是比较版本字符串。将回退逻辑集中保留在捆绑包中的一个位置。
将私有兼容 API 和捆绑包的回退作为相互独立的发布更改分别移除。在每次移除之前,重复进行消费者检查和版本检查。计划移除的版本只是一个审查节点,并不能证明已部署的捆绑包已经完成更新。
区分公共 API 与私有 API
生产环境的公共 API 遵循向后兼容政策。
新捆绑的包不得使用私有 API。仓库的 lint 检查和捆绑包检查会标记新增的直接和间接使用,但它们无法更改已经部署的旧捆绑包。
私有 API 可以被移除。临时的兼容路径不会将私有 API 变为公共 API。仅在受支持的旧捆绑包需要它时才保留它。在替代方案发布且必需的组合通过测试之后再将其移除,或者明确说明支持方面的变更。
识别包身份问题
导出回退无法修复包身份问题。由一个包副本创建的 React 上下文无法为使用另一个副本的消费者提供值。由一个副本创建的私有 API 锁也具有同样的限制。
对于这些情况,请使用不共享包局部状态的 API。否则,请更改入口点或受支持的 WordPress 版本,使双方使用同一个包副本。
Gutenberg 中的示例
ThemeProvider
#78958 中的 ThemeProvider 更改在同一版本中将该 API 公开并移除了其私有路径。已发布的捆绑包随即损坏。
#79594 恢复了私有路径。随后 #79620 在消费者迁移期间同时保留了两个路径。
DataViews
#81230 中的 DataViews 清理讨论发现了相反的问题。较新的 WordPress 运行时移除私有 @wordpress/components API 之后,较旧的捆绑 @wordpress/dataviews 包仍可能请求该 API。
#82221 为这些较旧的捆绑包恢复了选择性加入机制。但捆绑的 @wordpress/private-apis 副本仍然无法解锁由不同运行时副本创建的对象。