首页
/ React Router 开放治理模型:从指导委员会到六阶段 RFC 的功能落地流程

React Router 开放治理模型:从指导委员会到六阶段 RFC 的功能落地流程

2026-09-05 23:36:03作者:牧宁李

React Router 自 Remix 并入之后,从"创始开发者主导"转向了以指导委员会(Steering Committee, SC)为核心的开放治理模型,并通过一套参照 TC39 设计的六阶段 RFC 漏斗决定每个新功能的生死。本文基于仓库根目录的 GOVERNANCE.md 展开,结合仓库中的实际流程工件(bug 报告测试模板、变更文件工具链、ADR 目录等),讲清如何提交 Bug、如何推动一个新特性从 Proposal 走到 Stable,以及这一套流程在会议记录中的真实运转痕迹。

一、治理模式是如何形成的

从项目文档记载看,React Router 自 2014 年起长期由 Michael Jackson 与 Ryan Florence 主导开发。2021 年 Remix 发布、Remix 团队组建,再到 Remix v2 与 React Router v7 合并,项目的治理结构随之从 Founder-Leader(创始开发者领导)模型切换为 Steering Committee 模型,日常运转依赖 Request for Comments(RFC)流程。

GOVERNANCE.md 被明确定位为一份 evergreen 文档——它会随流程变化持续更新,目标是说清两件事:项目将如何继续演进,以及新特性以何种方式进入代码库。配套的 API 开发策略文档 则从使用者视角解释了同一套机制的落地产物:unstable 标志与 future 标志。

二、五条设计目标:评估 RFC 的基准

文档给出五条设计目标,任何 RFC 在被接受时都应对照考量:

  1. Less is More(少即是多):React Router 这些年积累了大量功能,也带来了大量 API 表面。方向是聚焦核心功能、在不牺牲能力的前提下收缩 API 表面——例如把若干既有 API 收敛为一个,或弃用旧 API 改用新的 React API。
  2. Routing and Data Focused(以路由与数据为中心):聚焦与路由器深度集成的核心 API,避免添加那些本可以在用户代码中自行实现的一等 API。
  3. Simple Migration Paths(平滑迁移路径):大版本升级不应该痛苦。破坏性变更应放在 future flag 之后;弃用应提前在代码和文档中明确标注;大版本发布前应先加入 Console 警告,引导开发者提前开始适配。
  4. Lowest Common Mode(最低共同模式):功能应加在尽可能低的使用模式上(declarative -> data -> framework),再被上层模式复用,确保最大数量的 React Router 应用可以受益。
  5. Regular Release Cadence(规律的发版节奏):目标大约每年发布一个 SemVer 大版本,让应用开发者有足够时间提前准备。

仓库中的工件能佐证这些目标不是空话:

  • decisions/ 目录以 ADR(Architecture Decision Records)形式归档了已定案的重要决策,编号从 0001-use-blocker.md 一直到 0016-plan-remove-agnostic-types.md,并提供了统一的 模板(Context / Decision / Consequences 三段式),对应"Less is More"下对 API 决策的书面留痕。
  • 2025-11-04 的 SC 会议记录确认了大版本节奏的具体化:"计划 v8 落在 2026 年 Q2,与 Node 20 的 EOL 对齐;此后目标是在每年同一 Q2 窗口发布大版本"。而当前仓库快照中 packages/react-router/package.json 的版本号已是 8.3.0,说明"每年一个大版本"的设计目标已经从计划变成了现实。

三、指导委员会(SC):职责与运作方式

SC 的三项核心职权:

  • 接受 RFC 进入"考虑"阶段;
  • 批准以"unstable"状态落地特性的 PR;
  • 批准将特性稳定化(stabilization)的 PR。

初始成员为原 Remix 团队开发者共 7 人:Matt Brophy(@brophdawg11)、Pedro Cattori(@pcattori)、Mark Dalgleish(@markdalgleish)、Jacob Ebey(@jacob-ebey)、Brooks Lybrand(@brookslybrand)、Sergio Xalambrí(@sergiodxa)、Bryan Ross(@rossipedia)。文档同时说明,未来可能会有限度地吸纳深度参与的社区成员加入 SC。

为降低协作摩擦,SC 主要通过 GitHub 异步工作,必要时再安排私下或公开的会议。

四、Bug/Issue 流程:"最小且可运行"的复现

由于使用 React Router 的应用数量庞大,文档要求对 Issue 提交保持严格,避免 GitHub 过载:

  • 所有 Bug 必须有**最小(minimal)且可运行(runnable)**的复现:
    • 最小:不是指向一个部署站点或你现有应用中的某个分支;
    • 可运行:是一个能看到问题的工作应用,而不是需要手工拼装的几段代码;
    • 首选复现方式:
      • Framework Mode:StackBlitz,或一个基于 integration/bug-report-test.ts 的、带失败集成测试的 GitHub fork;
      • Data/Declarative Modes:CodeSandbox 模板(TS 或 JS);
    • 如果 StackBlitz/CodeSandbox 不可行,基于全新 npx create-react-router 应用生成的 GitHub 仓库也可以接受;
    • 只有在极其特殊的情况下,才会接受代码片段或"最大复现"。
  • Issue 审查:不满足上述标准的 Issue 会被关闭并指回本文档;非 Issue(功能请求、使用问题)同样会被关闭并给出链接;SC 会定期分诊(triage)。
  • 修复 Issue:SC 会给优质的社区 Issue 打上 Accepting PRs 标签,这类 Issue 通常是面小、易于修复的;任何人都可以处理任何 Issue,但如果改动面太大、核心成员来不及快速评审,则不保证 PR 被接受。

仓库里的"失败测试"模板

docs/community/contributing.md 明确把"一个带失败测试的 PR"列为 Bug 报告的最好形式,并特别警告:不要以 PR 的形式直接发起新功能——新功能必须走本文档的流程。仓库为此内置了一个专门的模板文件 integration/bug-report-test.ts,其开头注释就是一份操作指南:

  • 你不需要修好 Bug,这个 PR 只需要"失败",用于让团队看到错误行为;如果你恰好有修复方案,要在后续 commit 中应用,并把此时变绿的测试移入正式测试文件;
  • 模板基于 Playwright 构建:test.beforeEach 中对 .data 请求注入 50ms 延迟以稳定测试,createFixture 用内联的 app/routes/_index.tsxapp/routes/burgers.tsx 组装一个真实应用,再由 createAppFixture 交给 Playwright 驱动页面交互;
  • 模板注释给出完整的本地运行方式:
pnpm install && pnpm build
# 如未装过 Playwright 浏览器内核:
pnpm exec playwright install chromium
# 运行这个 bug 报告测试:
pnpm test:integration bug-report --project chromium
# 加 --watch 可在文件变化时自动重跑
pnpm test:integration bug-report --project chromium --watch

五、新功能流程:六阶段 RFC 漏斗

新特性的流程"大致基于 TC39 流程"。文档强调两点:进入某个阶段并不意味着 RFC 一定会走到后面(阶段是一个漏斗,越少数的 RFC 能进入越靠后的阶段,只有最强的 RFC 才会以稳定形式进入发布);大多数社区驱动的功能会走完全部阶段,但若某功能足够 trivial/显而易见,可以跳级直接以稳定功能实现。

阶段总览

阶段 名称 进入条件 目的
0 Proposal(提案) 在 GitHub 上开启 Proposal 讨论 以 GitHub 提案作为最低的 RFC 提交门槛。任何人都可以提交,社区可以评审、评论、点赞,且初期不需要 SC 参与。
1 Consideration(考虑) 获得 2 名 SC 成员接受提案 第一道"漏斗":SC 正式表达对热门 RFC 的兴趣。仅需 2 名成员表态即可进入考虑阶段,以便低摩擦地在 Alpha 阶段试验特性。
2 Alpha(试验) 开一个以 "unstable" 状态实现该特性的 PR 下一道漏斗。SC 表态兴趣后,开放一个示例 PR 实现,让社区成员在不依赖任何 SemVer 发布的情况下进行 alpha 测试。此阶段用于在实际应用中评估 RFC、考察务实的代码实现形态。
3 Beta(公测) 2 名 SC 成员批准该 PR(认可其作为不稳定 API) SC 成员不仅对 beta 特性代码满意,还看到 alpha 测试者的正面反馈后,RFC 进入 Beta。Alpha 阶段 PR 攒够 SC 批准即可合并,并进入下一个 React Router 发布。
4 Stabilization(稳定化) 在 Beta 阶段至少停留 1 个月,且开一个稳定化 API 的 PR;PR 应同时包含新功能的文档 确保不稳定特性有足够时间供应用方升级版本并选择 beta 测试,不赶进度,以便在稳定化前获得最大量的反馈。
5 Stable(稳定) 至少 50% 的 SC 成员批准稳定化 PR SC 不仅认可稳定特性的代码,还看到 beta 测试者的正面反馈。Beta 阶段 PR 攒够批准并满足 Beta 最低时长后即可合并,进入下一个 React Router 发布。

文档还说明:特性一旦到达 Stage 2,就会被加入官方 Roadmap 供社区跟踪其阶段进展。

Stage 0 — Proposal

  • 所有新功能都从 Stage 0 开始:以 RFC 形式写在 GitHub Proposal Discussion 中;
  • 任何人都可以写 RFC,包括核心团队成员和社区成员;
  • RFC 应说明:新特性的使用场景、为什么现有 API 不足以覆盖该场景,并给出候选的 API 形态;
  • 提案应清晰、简洁,提供足够上下文供 SC 与社区评估其价值;
  • 社区点赞是兴趣与需求的信号——点赞更高的提案更可能被 SC 考虑;
  • 此阶段社区成员可以在 fork 中做示例实现并在 RFC 中贴链接,但不应在达到 Stage 1 之前开 PR。

Stage 1 — Consideration

  • 当 2 名 SC 成员表示支持该想法是 React Router 的有价值补充时,提案进入 Stage 1;
  • 这两位初始支持者成为该特性的"champion",松散地负责护送特性走过后续阶段;
  • 此阶段提案有资格获得来自核心团队或社区成员的示例 PR;
  • SC 会在此阶段明确该特性是接受社区 PR,还是核心团队自己来做;
  • 若接受社区 PR,会给 RFC 加 accepting-prs 标签;
  • 此阶段的所有 PR 都应以"unstable"方式实现(通常是对 future flag 或 API 使用 unstable_ 前缀)。

Stage 2 — Alpha

  • PR 以 unstable_ 状态实现该特性后,提案进入 Stage 2;
  • 此时应为该 Proposal 开一个 Issue 并加入 Roadmap;移除 accepting-prs 标签、加上 🗺️ Roadmap 标签,表示该 RFC 正式进入路线图;
  • 此阶段的核心是:在合并任何代码之前寻找早期社区测试,因此 PR 需要提供一种让社区成员选择加入 alpha 测试的机制:
    • 维护者可以给 PR 分支加 alpha-release 标签触发一次 alpha 实验性发布,并把结果评论回 PR;
    • 由于 alpha 发布可能包含已提交到 dev 但尚未随稳定版发布的其他工作,某些场景下并不适合测试;
    • 这种情况下,PR 作者也可以在评论里附上 .patch 文件内容,社区可以用 patch-package 或 pnpm patch 应用;
  • alpha 测试者的反馈是继续推进的必要条件;
  • PR 还应包含一个 changes 文件,用于记录新 API 以进入 release notes;
  • SC 成员通过 GitHub review 评审并批准 PR。此阶段的批准传达四层含义:特性对 React Router 有价值;API/代码足以进入 unstable/beta 测试(尽管可能还要迭代);代码不必是最终形态,但不能对其他 API 区域引入回归;alpha 测试者的正面反馈已经足够。

Stage 3 — Beta

  • 拿到 2 名 SC 成员的 Stage 2 PR 批准并合并到 dev 后,提案进入 Stage 3;
    • 如果 unstable_ PR 的作者本身就是 SC 成员,其作者身份算作一次隐式批准,此时还需要另外 1 名 SC 成员的显式批准;
  • 特性随下一个正常 SemVer 发布进入更广泛的 beta 测试,位于 unstable_ 标志之后。

Stage 4 — Stabilization

  • 在 Stage 3 至少停留 1 个月后,开一个移除 unstable_ 前缀、稳定化特性的 PR,提案进入 Stage 4;
  • 稳定化 PR 应补上该功能的正式文档;
  • SC 成员通过 GitHub review 评审批准。此阶段的批准传达三层含义:beta 测试者反馈已足以让人信任 API 的设计与实现;代码达到生产质量、测试充分且无相关回归;PR 包含稳定功能的文档。

Stage 5 — Stable

  • 拿到至少 50% SC 成员的 Stage 4 PR 批准并合并到 dev 后,提案进入 Stage 5;
    • 稳定化 PR 的作者是 SC 成员时,其作者身份算一次隐式批准;
  • 稳定特性随下一个正常 SemVer 发布进入正式版本。

六、unstable 标志与变更文件:流程在代码中的落点

Stage 1–5 并非只在文档里流转,仓库中有对应的机制支撑:

unstable 与 future 标志的区分。 docs/community/api-development-strategy.md 把标志分为两类:破坏性 API 变更先以 future flag 形式引入,让用户在大版本前逐个 opt-in;而 unstable flag 用于尚在设计的特性——不推荐用于生产、可能无预警变更、可能有 Bug、没有文档、甚至可能被整体放弃。该文档还给出了版本策略:unstable 标志因为是"非新稳定 API",随 SemVer patch 版本发布;当它稳定为 future flag 时,则以 minor 版本发布并补充文档。这与 GOVERNANCE 中 Stage 2/3 的 unstable_ 前缀、Stage 4 的"移除前缀 + 补文档"直接对应。从源码结构看,unstable_ 前缀 API 在仓库中真实存在并被持续测试,例如 packages/react-router/index.tspackages/react-router/lib/hooks.tsx 中的 unstable 系列 hook,以及配套测试 packages/react-router/tests/unstable-useRouterState-test.tsx;框架模式的 unstable 配置项(如 unstable_splitRouteModulesunstable_optimizedDeps)则在 packages/react-router-dev/config/config.ts 中定义。

changes 文件与版本推进。 Stage 2 要求"PR 应包含 changes 文件",这一要求在 docs/community/contributing.md 中有更具体的规定:所有对用户有影响的 PR 都应在相关包的 packages/<package>/.changes/ 目录下生成变更文件,可用 pnpm run changes:add 工具生成;文件命名为 <type>.<short-description>.md,type 取 patchminormajorunstable 四种之一,例如:

patch.fix-fetcher-redirects.md
minor.add-some-new-api.md
major.require-node-24.md
unstable.update-unstable-api.md

解析与校验逻辑集中在 scripts/changes/changes.tsbumpTypes 定义了四种 bump 类型;parsePackageChanges 会校验文件名前缀、文件非空、首行不能以 - 开头的 bullet 开头(changelog 会自动加 bullet)、内部标题只能是 4–6 级、带 BREAKING CHANGE: 前缀的内容必须用 major. 前缀等。发布侧采用锁步(lock-step)版本策略——generateCommitMessage 直接以 Release v<nextVersion> 生成提交信息,DEVELOPMENT.md 则描述了整套自动化:main 分支上出现 changes 文件即触发 release 工作流,创建 release-v<major>-pr 分支、更新版本、生成 changelog、删除 changes 文件并开 PR,合并后再自动发布到 npm、打 tag、创建 GitHub Release。也就是说,GOVERNANCE 中"Stage 3 进入下一个正常 SemVer 发布"这句话,最终是由这套工具链兑现的。

七、从会议记录看流程的实际运转

GOVERNANCE.md 的"Meeting Notes"一节是 SC 会议的持续归档区,文档内甚至内嵌了笔记模板(<details> 折叠块 + YYYY-MM-DD Meeting Notes 标题)。当前文档中已归档六次会议(2025-09-08、2025-09-23、2025-11-04、2025-11-18、2025-12-02、2025-12-16),它们恰好是上述流程运转的样本:

日期 关键结论(节选)
2025-09-08 复盘 Roadmap:middleware 与 context 已合并进 dev 等待 7.9.0 预发布;onError 已在 7.8.2 发布且表现符合预期;RSC 框架模式接近完成、剩余渲染期错误处理;讨论 observability 与 OpenTelemetry 的集成路径;决定聚焦在途事项,不再接收新提案(当时已有 10+ 提案在处理中)。
2025-09-23 宣布 7.9.2 将发布 unstable 的 RSC 框架模式支持与 fetcher.unstable_reset() API;评审 instrumentRouter/instrumentRoutes 的 POC,并讨论改为只读信息子集以防用户篡改 handler 参数;推进 2 个新 RFC 进入"考虑"阶段(Prerender concurrency、Per-route Layout component)。
2025-11-04 评审 v8 开放提案:确认改为 ESM-only 构建;计划 v8 落在 2026 Q2 并与 Node 20 EOL 对齐,v8 最低 Node 版本 22.12;此后每年同一 Q2 窗口发大版本;SRI 准备稳定化但需先征询既有用户;unstable_optimizedDeps 在 v8 保持 unstable;RSC 实现不进 v8 稳定 API。
2025-11-18 启动 fetcher.reset 与客户端 onError 的稳定化 PR;确认 split route modulesenvironment API 可批量稳定化;讨论类型安全 fetcher(route ID vs pattern、拆分为 useRouteLoader/useRouteAction、借助 React 19 的 useTransition/useOptimistic 瘦身状态抽象)以及"default revalidate"的调用点设计。
2025-12-02 三项稳定化落地:environment APIsplit route modulesfetch error reset 的 future flag;onError 待内部重构解决 strict mode 下可能的双重上报后随下个版本发布;讨论 Babel 转 SWC/Oxide 的性能提案(需要更多瓶颈证据);讨论 fetcher 错误不向路由级错误边界冒泡的 opt-in 机制、路由 masking/rewrites、非 window 元素的滚动恢复等提案。
2025-12-16 修复尾斜杠导致 loader/action 收到不一致请求路径的 Bug:数据请求 URL 改为 /_a/b/c/_.data 形态(原为 _root.data 风格),因可能破坏缓存规则而放在 future flag 之后,opt-in 且基本非破坏。

这些记录展示了文档中每个流程条款的实例:Stage 2 的 alpha 试验(RSC 框架模式以 unstable 状态先入 7.9.2)、Stage 4 的稳定化批次(三个 future flag 一起批处理)、以 future flag 承载潜在破坏性变更(尾斜杠数据请求格式)——与 GOVERNANCE.md 的设计目标"破坏性变更应放在 future flag 之后"逐条对应。

八、小结:一套可对照仓库验证的流程

React Router 的开放治理模型可以浓缩为三条主线:

  1. 准入:Bug 必须"最小且可运行"(首选 integration/bug-report-test.ts 式的失败测试 PR);新功能必须从 Proposal 讨论起步,而不是直接开 PR。
  2. 分级推进:Stage 0→5 的漏斗中,unstable_ 前缀承载 Stage 1–3 的实验期,changes 文件(patch/minor/major/unstable)驱动 SemVer 推进,Stage 4 强制"Beta 至少 1 个月 + 文档齐备",Stage 5 要求 50% SC 批准。
  3. 留痕与节奏decisions/ 目录的 ADR、GOVERNANCE.md 内嵌的会议纪要、以及 DEVELOPMENT.md 描述的自动化发布管线,共同让"每年一个大版本、破坏性变更走 future flag"成为可执行、可审计的制度,而不只是一句口号。

对贡献者而言,实际可操作的入口很明确:Bug 找 integration/bug-report-test.ts,新 API 找 GitHub Proposal Discussion 并阅读 GOVERNANCE.mddocs/community/contributing.md,PR 中记得带上 changes 文件,剩下的交给漏斗。

登录后查看全文
热门项目推荐
相关项目推荐