React Canaries:在 Meta 之外实现增量功能部署

2023 年 5 月 3 日,Dan AbramovSophie AlpertRick HanlonSebastian MarkbågeAndrew Clark 发布


我们希望为 React 社区提供一个选择,让他们能够在新功能设计接近最终版本后立即采用,而无需等到稳定版本发布,类似于 Meta 长期以来一直在内部使用 React 的前沿版本。我们正在推出一个新的官方支持的 Canary 发布渠道。它允许框架等精选设置将 React 各个功能的采用与 React 发布计划分离。


tl;dr

  • 我们正在为 React 推出一个官方支持的 Canary 发布渠道。由于它得到了官方支持,如果出现任何回归,我们将像对待稳定版本中的错误一样紧急处理它们。
  • Canaries 允许您在新功能登陆语义化版本控制的稳定版本之前就开始使用它们。
  • 实验性 渠道不同,React Canaries 只包含我们合理认为可以采用的功能。我们鼓励框架考虑捆绑固定的 Canary React 版本。
  • 我们将在我们的博客上宣布重大更改和新功能,因为它们会出现在 Canary 版本中。
  • 与往常一样,React 继续遵循每个稳定版本的语义化版本控制。

React 功能通常是如何开发的

通常,每个 React 功能都要经历相同的阶段

  1. 我们开发了一个初始版本,并在其前面加上 experimental_unstable_ 前缀。该功能仅在 experimental 发布渠道中可用。在这一点上,预计该功能将发生重大变化。
  2. 我们在 Meta 找到一个愿意帮助我们测试此功能并提供反馈的团队。这导致了一系列的变化。随着该功能变得更加稳定,我们与 Meta 的更多团队合作进行试用。
  3. 最终,我们对设计充满信心。我们从 API 名称中删除了前缀,并默认在 main 分支上提供该功能,大多数 Meta 产品都使用该功能。在这一点上,Meta 的任何团队都可以使用此功能。
  4. 当我们对方向建立信心时,我们还会为新功能发布 RFC。在这一点上,我们知道该设计适用于广泛的用例,但我们可能会在最后一刻进行一些调整。
  5. 当我们即将发布开源版本时,我们会为该功能编写文档,并最终在稳定的 React 版本中发布该功能。

对于我们迄今为止发布的大多数功能来说,这本 playbook 都运行良好。然而,在该功能通常可以使用 (步骤 3) 和在开源中发布 (步骤 5) 之间可能存在很大差距。

我们希望为 React 社区提供一个选择,让他们可以像 Meta 一样,更早地采用新的个人功能(当它们可用时),而无需等待 React 的下一个发布周期。

与往常一样,所有 React 功能最终都将进入稳定版本。

我们不能只是发布更多的小版本吗?

通常,我们确实使用小版本来引入新功能。

然而,这并不总是可行的。有时,新功能与其他尚未完全完成且我们仍在积极迭代的新功能相互关联。我们不能单独发布它们,因为它们的实现是相关的。我们不能对它们进行单独的版本控制,因为它们会影响相同的包(例如,reactreact-dom)。我们需要保持迭代未准备好部分的能力,而无需发布大量的主要版本,而语义化版本控制要求我们这样做。

在 Meta,我们通过从 main 分支构建 React,并每周手动将其更新到特定的固定提交来解决这个问题。这也是 React Native 版本在过去几年中一直遵循的方法。每个稳定版本的 React Native 都固定在 React 存储库的 main 分支中的特定提交上。这使得 React Native 能够包含重要的错误修复,并在框架级别增量采用新的 React 功能,而无需耦合到全局 React 发布计划。

我们希望将此工作流程提供给其他框架和精选设置。例如,它允许 React 之上的框架在重大更改包含到稳定的 React 版本中之前包含与 React 相关的重大更改。这特别有用,因为某些重大更改只影响框架集成。这使得框架可以在不破坏语义化版本控制的情况下在其自己的次要版本中发布此类更改。

通过 Canaries 渠道进行滚动发布将使我们能够拥有更紧密的反馈循环,并确保新功能在社区中得到全面的测试。此工作流程更接近于 JavaScript 标准委员会 TC39 处理分阶段变更 的方式。新的 React 功能可能会在基于 React 构建的框架中先于 React 稳定版本提供,就像新的 JavaScript 功能会在正式批准成为规范的一部分之前先在浏览器中发布一样。

为什么不使用实验版本?

尽管从技术上讲,您可以使用 实验版本,但我们建议不要在生产环境中使用它们,因为实验性 API 在走向稳定的过程中可能会经历重大的破坏性变更(甚至可能会被完全移除)。虽然 Canaries 版本也可能包含错误(与任何版本一样),但展望未来,我们计划在我们的博客上宣布 Canaries 版本中的任何重大破坏性变更。Canaries 版本最接近 Meta 内部运行的代码,因此您通常可以预期它们相对稳定。但是,您确实需要在更新固定提交之间保持版本固定并手动扫描 GitHub 提交日志。

我们预计,大多数在精心策划的设置(如框架)之外使用 React 的人都希望继续使用稳定版本。但是,如果您正在构建框架,则可能需要考虑捆绑固定到特定提交的 React Canary 版本,并按照您自己的节奏更新它。这样做的好处是,它可以让您更早地为您的用户发布单独完成的 React 功能和错误修复,并按照您自己的发布时间表进行,类似于 React Native 在过去几年中所做的那样。缺点是您将承担额外的责任,以审查哪些 React 提交被引入,并向您的用户传达您的版本中包含哪些 React 变更。

如果您是框架作者并且想尝试这种方法,请与我们联系。

尽早宣布重大变更和新功能

Canary 版本代表了我们在任何给定时间对下一个稳定 React 版本的最佳猜测。

传统上,我们只会在发布周期的末尾(发布主要版本时)宣布重大变更。现在,Canary 版本是使用 React 的官方支持方式,我们计划转变为在 Canaries 版本中落地时宣布重大变更和重要的新功能。例如,如果我们合并了一个将在 Canary 版本中发布的重大变更,我们会在 React 博客上写一篇关于它的文章,并在必要时包括代码修改和迁移说明。然后,如果您是一位框架作者,正在发布一个主要版本,该版本更新了固定的 React Canary 版本以包含该变更,则可以从您的发行说明中链接到我们的博客文章。最后,当 React 的稳定主要版本准备好后,我们将链接到那些已发布的博客文章,我们希望这将有助于我们的团队更快地取得进展。

我们计划在 Canaries 版本中落地时记录 API,即使这些 API 在 Canaries 版本之外尚不可用。仅在 Canaries 版本中可用的 API 将在相应页面上标有特殊说明。这将包括像 use 这样的 API,以及我们将为其发送 RFC 的其他一些 API(如 cachecreateServerContext)。

Canaries 版本必须固定

如果您决定为您的应用程序或框架采用 Canary 工作流程,请确保始终固定您正在使用的 Canary 版本的确切版本。由于 Canaries 版本是预发布版本,因此它们可能仍包含重大变更。

示例:React 服务器组件

正如我们 在 3 月份宣布的那样,React 服务器组件规范已经最终确定,我们预计与其面向用户的 API 契约相关的重大变更不会很大。但是,我们还不能在 React 的稳定版本中发布对 React 服务器组件的支持,因为我们仍在研究几个相互关联的仅限框架的功能(例如 资源加载),并且预计那里会有更多重大变更。

这意味着 React 服务器组件已准备好被框架采用。但是,在下一个 React 主要版本发布之前,框架采用它们的唯一方法是发布固定版本的 React Canary 版本。(为了避免捆绑两个 React 副本,希望这样做的框架需要强制将 reactreact-dom 的解析固定到与其框架一起发布的固定 Canary 版本,并向其用户解释这一点。例如,这就是 Next.js App Router 所做的。)

针对稳定版本和 Canary 版本测试库

我们不要求库作者测试每一个 Canary 版本,因为这将非常困难。但是,就像我们 三年前最初引入不同的 React 预发布渠道时一样,我们鼓励库针对最新的稳定版本和最新的 Canary 版本运行测试。如果您发现未经宣布的行为发生变化,请在 React 代码仓库中提交错误报告,以便我们帮助诊断。我们预计,随着这种做法被广泛采用,将减少将库升级到 React 新主要版本所需的工作量,因为意外的回归会在它们落地时被发现。

注意

严格来说,Canary 并不是一个新的发布渠道,它以前被称为 Next。但是,我们决定对其进行重命名,以避免与 Next.js 混淆。我们正在将其宣布为一个新的发布渠道,以传达新的期望,例如 Canaries 成为使用 React 的官方支持方式。

稳定版本的运作方式与之前相同

我们没有对稳定的 React 版本引入任何更改。