Awesome Copilot React 19 Upgrade 插件:React 18 到 React 19 企业级迁移工具链实战指南
本指南围绕开源仓库 awesome-copilot 中的 react19-upgrade 插件(插件清单、插件文档)展开,讲解如何借助其内置的 5 个 Agent 与 3 个 Skill 完成 React 18 代码库到 React 19 的体系化升级。读完本文,你将掌握从代码审计、依赖升级、源码迁移到测试修复的完整四阶段迁移管线,并了解 React 19 中所有破坏性变更与可选现代化改造的具体落地写法。
插件概览:专为 React 18 → 19 设计的迁移编排
react19-upgrade 是一个面向企业级代码库的 React 19 迁移工具包,核心思路是"专业分工 + 门禁把关":不依赖单一 Agent 一次性处理所有问题,而是将迁移拆解为 审计(Audit)→ 依赖(Deps)→ 源码迁移(Migrate)→ 测试(Tests) 四个阶段,每个阶段由专门的 Agent 负责,并由主协调器 react19-commander 在阶段之间设置验证门禁(Gate),确认通过后才允许进入下一阶段。
插件元数据定义在 plugins/react19-upgrade/plugin.json 中,其 extensions 区块声明了 5 个 Agent 文件与 3 个 Skill 目录:
- Agents:
react19-auditor、react19-commander、react19-dep-surgeon、react19-migrator、react19-test-guardian; - Skills:
react19-concurrent-patterns、react19-source-patterns、react19-test-patterns。
整体工作流在 agents/react19-commander.agent.md 中定义为严格的串行管线,明确"每次只调用一个子 Agent,禁止并行"。
安装与快速启动
在 GitHub Copilot 环境中通过以下命令安装该插件:
copilot plugin install react19-upgrade@awesome-copilot
安装完成后,直接向 Copilot 发起指令即可激活迁移:
Ask: "Start implementing React 19 migration for my codebase"
随后 react19-commander 会引导你依次完成:
- Audit → 识别全部破坏性变更与弃用模式;
- Deps → 升级到 react@19 及兼容库;
- Migrate → 修复所有弃用 API 与模式;
- Tests → 迁移测试套件并运行至全绿。
五大 Agent 分工详解
react19-commander:全管线主协调器
react19-commander(agents/react19-commander.agent.md)是整个迁移的"总指挥",拥有子 Agent 调度、终端执行、文件编辑、代码搜索与问题读取等工具权限,并通过 vscode/memory 工具实现跨会话的状态持久化。
内存协议(Memory Protocol) 是其可恢复性的关键:
# 每次会话开始先读取迁移状态
#tool:memory read repository "react19-migration-state"
# 每个门禁通过后写入状态
#tool:memory write repository "react19-migration-state" "[state JSON]"
状态对象采用如下结构:
{
"phase": "audit|deps|migrate|tests|done",
"auditComplete": true,
"depsComplete": false,
"migrateComplete": false,
"testsComplete": false,
"reactVersion": "19.x.x",
"failedTests": 0,
"lastRun": "ISO timestamp"
}
启动时,commander 先读取内存、再探测当前 React 版本:
node -e "console.log(require('./node_modules/react/package.json').version)" 2>/dev/null || cat package.json | grep '"react"'
随后向用户报告哪些阶段已完成、哪些待办,并从第一个未完成阶段继续——这意味着中途断线不会导致已完成的工作白做。
管线四阶段与门禁如下:
| 阶段 | 调用的子 Agent | 门禁(Gate)条件 |
|---|---|---|
| Phase 1 Audit | react19-auditor |
.github/react19-audit.md 存在,且返回了问题总数 |
| Phase 2 Deps | react19-dep-surgeon |
返回 GO,react@19.x.x 确认,npm ls 无 peer 错误 |
| Phase 3 Migrate | react19-migrator |
源码(非测试文件)中弃用模式计数为 0 |
| Phase 4 Tests | react19-test-guardian |
测试输出为 Tests: X passed 且 0 失败 |
Phase 4 通过后,commander 还会亲自执行最终验证门禁,运行构建与全量测试:
echo "=== FINAL BUILD ==="
npm run build 2>&1 | tail -20
echo "=== FINAL TEST RUN ==="
npm test -- --watchAll=false --passWithNoTests --forceExit 2>&1 | grep -E "Tests:|Test Suites:|FAIL|PASS" | tail -10
只有构建退出码为 0 且测试 0 失败才算 COMPLETE;若任一失败,commander 会定位是哪个阶段引入的回归,并携带具体错误上下文重新调用对应子 Agent。
交战规则同样值得留意:绝不跳过门禁(子 Agent 声称完成不算数,必须用命令验证)、绝不虚构完成状态、调用子 Agent 时始终传递完整上下文、善用内存实现会话恢复。迁移清单(Migration Checklist)完全由内存跟踪,涵盖从审计报告生成到构建成功的 20 余项检查点。
react19-auditor:只读不写的深度扫描器
react19-auditor(agents/react19-auditor.agent.md)被设计为"外科手术式扫描器":读取一切、修复零文件,产出唯一的交付物是审计报告。它同样支持内存断点续扫(react19-audit-progress 键)。
扫描协议分四个阶段:
- Phase 1 依赖审计:读取 package.json 中所有 react 相关依赖(react、testing、jest、apollo、emotion、router),并用
npm ls排查 peer 冲突; - Phase 2 移除 API 扫描(必须修复):对
ReactDOM.render、ReactDOM.hydrate、unmountComponentAtNode、findDOMNode、createFactory、react-dom/test-utils导入、Legacy Context(contextTypes/childContextTypes/getChildContext)、字符串 ref(this.refs.)逐项 grep; - Phase 3 弃用模式扫描(可选现代化):
forwardRef、函数组件上的defaultProps、无初始值的useRef()、propTypes计数、无用的import React from 'react'; - Phase 4 测试文件扫描:错误位置的
act导入、Simulate.用法、react-test-renderer、以及toHaveBeenCalledTimes断言(StrictMode 调用次数可能需调整)。
扫描完成后,auditor 将结果写入 .github/react19-audit.md,报告按 🔴 Critical(破坏性)、🟡 Deprecated(应迁移)、🔵 Test-specific(测试相关)、ℹ️ Informational(无需改码)四类组织,并给出按优先级排序的 18 步迁移计划(先升依赖、再改源码、最后修测试)。值得注意的是,报告对 propTypes 与 StrictMode 行为变化做了专门说明:React 19 移除了内置的 propTypes 运行时校验,但 prop-types 包仍可独立工作;StrictMode 不再双调用 effect,因此依赖 ×2/×4 计数的 spy 断言需要实测更新。
react19-dep-surgeon:零冲突的依赖升级专家
react19-dep-surgeon(agents/react19-dep-surgeon.agent.md)的目标是把依赖树升级到与 React 19 完全兼容且 0 peer 冲突。升级路径分六步:
- 升级 React 核心:
npm install --save react@^19.0.0 react-dom@^19.0.0,并用node -e确认两者版本均为 19.x.x,否则停止排查; - 升级 Testing Library:安装
@testing-library/react@^16.0.0、@testing-library/jest-dom@^6.0.0、@testing-library/user-event@^14.0.0。理由很关键:RTL 14 及以下版本内部仍使用ReactDOM.render,与 React 19 不兼容; - 升级 Apollo Client(如存在):
npm install @apollo/client@latest; - 升级 Emotion(如存在):
npm install @emotion/react@latest @emotion/styled@latest; - 解决全部 peer 冲突:用
npm ls定位违规包,逐一npm install <package>@latest复检。禁止使用--force;--legacy-peer-deps仅作为最后手段使用,且必须在 package.json 的_notes字段中记录说明;若某包没有 React 19 兼容版本,则明确记录并上报 commander; - 干净安装收尾:删除
node_modules与package-lock.json后重新npm install,确认npm ls中的 WARN/ERR/peer 行数为 0。
最终输出 GO/NO-GO 决策:仅当 react@19.x.x、react-dom@19.x.x、@testing-library/react@16.x 全部确认且 npm ls 无 peer 错误时才返回 GO。
react19-migrator:源码迁移引擎
react19-migrator(agents/react19-migrator.agent.md)依据审计报告逐文件重写源码中的弃用与移除 API,绝不触碰测试文件,且逐文件写内存检查点以便中断续跑。其迁移参考(M1–M11)完整覆盖了 README 中列出的所有模式,其中最重要的几个:
M1 ReactDOM.render → createRoot
// Before
import ReactDOM from 'react-dom';
ReactDOM.render(<App />, document.getElementById('root'));
// After
import { createRoot } from 'react-dom/client';
const root = createRoot(document.getElementById('root'));
root.render(<App />);
M2 ReactDOM.hydrate → hydrateRoot:import { hydrateRoot } from 'react-dom/client'; hydrateRoot(container, <App />)。
M3 unmountComponentAtNode → root.unmount():其中 root 是 createRoot(container) 的引用。
M4 findDOMNode → 直接 ref:函数组件用 useRef(null),类组件用 React.createRef(),统一通过 nodeRef.current 访问 DOM 节点。
M5 forwardRef → ref 作为直接 prop(可选现代化)
// Before
const Input = forwardRef(function Input({ label }, ref) {
return <input ref={ref} />;
});
// After(React 19 新范式)
function Input({ label, ref }) {
return <input ref={ref} />;
}
重要边界:forwardRef 在 React 19 中并未移除,属于可选改造而非强制。若组件契约依赖第二参数 ref 签名、或使用了 useImperativeHandle,保留 forwardRef 完全可行。这也与 auditor 的结论一致:forwardRef 只是"值得现代化",不是"必须修复"。
M6 函数组件 defaultProps → ES6 默认参数
// Before
function Button({ label, size, disabled }) { ... }
Button.defaultProps = { size: 'medium', disabled: false };
// After
function Button({ label, size = 'medium', disabled = false }) { ... }
// 彻底删除 Button.defaultProps 块
两条易错点:类组件不要迁移(defaultProps 在类组件上仍然有效);ES6 默认参数只在值为 undefined 时生效,不覆盖 null。
M7 Legacy Context → createContext:static contextTypes/childContextTypes/getChildContext() 替换为 const MyContext = React.createContext(defaultValue) + <MyContext value={...}> + static contextType = MyContext。
M8 字符串 ref → createRef:ref="myInput" + this.refs.myInput 改为类字段 myInputRef = React.createRef() 并绑定 ref={this.myInputRef}。
M9 useRef() → useRef(null):所有无参数调用一律补上 null 初始值。
M10 propTypes 注释(不删代码):在每个 .propTypes = {} 上方添加说明注释,强调 React 19 不再运行时校验、保留仅为文档与 IDE 用途。
M11 清理无用的 import React from 'react':仅当文件不使用 React.xxx 前缀、不是类组件时才能移除。
migrator 的执行规则包含一条对并发模式的安全红线:绝不改动 useTransition、useDeferredValue、Suspense、startTransition 等并发逻辑——迁移只应触碰 React API 表面(forwardRef、defaultProps 等),并完整保留 Emotion css/styled 调用、Apollo hooks 与全部注释。完成验证通过一组 grep 命令确认弃用模式计数为 0。
react19-test-guardian:跑不绿不罢休的测试修复器
react19-test-guardian(agents/react19-test-guardian.agent.md)负责把测试套件迁移到 React 19 兼容状态并运行至 0 失败。它的底线是:不跳过测试、不删除测试、不压制错误——如果某个测试连续 3 次修复失败,就写入审计报告的 "Blocked Tests" 区块并上报 commander。
其测试迁移参考(T1–T8)覆盖了测试侧的完整变化:
- T1
act导入修复:act不再从react-dom/test-utils导出,改为import { act } from 'react'; - T2
Simulate→fireEvent:Simulate.click/change/submit/keyDown全部替换为@testing-library/react的fireEvent对应方法; - T3
react-dom/test-utils全量导出映射:renderIntoDocument→ RTLrender,findRenderedDOMComponentWithTag/scryRenderedDOMComponentsWithTag→ RTL 查询(getByRole、getByTestId、getAllByRole),isElement、isCompositeComponent等直接删除; - T4 StrictMode spy 调用次数更新:React 18 StrictMode 下 effect 双调用(spy 计数 ×2/×4),React 19 只调用一次(×1/×2)。策略是实测而非猜测——跑失败用例,从错误信息读取真实计数再更新断言;且注意渲染阶段(组件函数体)的调用在 React 19 StrictMode 下仍是双调用,计数保持 ×2;
- T5
useRef形状更新:{ current: undefined }→{ current: null }; - T6 自定义 render helper 校验:确认测试工具函数用的是 RTL
render而非ReactDOM.render; - T7 错误边界测试更新:React 19 错误日志行为变化,
console.error从 React 18 的调用 2 次变为 1 次; - T8 异步
act()包裹:对 "not wrapped in act(...)" 警告,用await act(async () => { ... })包裹状态更新触发操作。
guardian 还内置了一张错误排查表,把常见失败与修法一一对应:
| 错误 | 原因 | 修复 |
|---|---|---|
act is not a function |
导入位置错误 | import { act } from 'react' |
Simulate is not defined |
导出已移除 | 替换为 fireEvent |
Expected N received M |
StrictMode 调用次数变化 | 跑测试后用真实计数 |
Cannot find module react-dom/test-utils |
包已被掏空 | 切换全部导入 |
cannot read .current of undefined |
useRef() 形状 |
补 null 初始值 |
not wrapped in act(...) |
异步状态更新 | 包裹 await act(async () => {...}) |
Warning: ReactDOM.render is no longer supported |
旧 render 残留在 setup | 更新为 createRoot |
执行循环为"按审计报告修一批 → 跑一次全量 → 逐个消灭 FAIL 文件"的迭代过程,直到 Tests: X passed 且无失败。
三大 Skill 配套
react19-concurrent-patterns:并发模式的"保留"与"采纳"
该 Skill(skills/react19-concurrent-patterns/SKILL.md)给出两条并行准则:
Part 1 保留:React 18 中已有的并发模式在迁移中绝不能被动摇——createRoot 正确写法、useTransition(React 19 中行为不变)、useDeferredValue(不变)、Suspense + React.lazy 代码分割(不变)都给出示例代码,并用 grep 校验迁移期间这些模式未被误改。
Part 2 采纳:迁移稳定后(而非迁移过程中)才值得引入的新 API——use() Hook、Actions 系列(useActionState、useFormStatus、useOptimistic)、以及用于数据获取的 Suspense 新模式,细节分别位于 skills/react19-concurrent-patterns/references/react19-use.md、skills/react19-concurrent-patterns/references/react19-actions.md 与 skills/react19-concurrent-patterns/references/react19-suspense.md。
react19-source-patterns:源码迁移快速参考
该 Skill(skills/react19-source-patterns/SKILL.md)把全部源码侧迁移浓缩为一张速查表:ReactDOM.render → createRoot().render()、ReactDOM.hydrate → hydrateRoot、unmountComponentAtNode → root.unmount()、findDOMNode → 直接 ref、forwardRef → ref 直接 prop、defaultProps → ES6 默认参数、useRef() → useRef(null)、Legacy Context → createContext、字符串 ref → createRef()、无用 React 导入 → 移除。完整的前后对照代码(含 forwardRef + useImperativeHandle、defaultProps 的 null/undefined 语义、跨文件的 Context Provider/Consumer 迁移等边界情况)在 skills/react19-source-patterns/references/api-migrations.md。
react19-test-patterns:测试迁移优先级指南
该 Skill(skills/react19-test-patterns/SKILL.md)强调测试修复有严格依赖顺序:先修 act 导入(解锁一切)→ 再改 Simulate → 清理全部 test-utils 导入 → 实测 StrictMode 计数 → 处理剩余 act 警告 → 最后逐代码库验证一次自定义 render helper。其中给出了混合导入的拆分写法(import { act, Simulate, renderIntoDocument } from 'react-dom/test-utils' 拆成 react 与 RTL 两行导入)以及更完整的 test-utils API 映射表。
React 18 → 19 破坏性变更清单
以下是迁移必须面对的完整变更全景(与 auditor 扫描模式、migrator 修复模式一一对应):
已移除的 API(必须修复)
| 已移除 API | 替代方案 |
|---|---|
ReactDOM.render() |
createRoot() |
ReactDOM.hydrate() |
hydrateRoot() |
ReactDOM.unmountComponentAtNode() |
root.unmount() |
ReactDOM.findDOMNode() |
直接 ref |
React.createFactory() |
JSX |
react-dom/test-utils 导出 |
act 移入 react,其余用 RTL 替代 |
Legacy Context API(contextTypes/childContextTypes/getChildContext) |
createContext |
字符串 ref(this.refs.x) |
createRef |
弃用但可用的模式(建议迁移)
forwardRef:ref 现在可作为直接 prop 传递,属可选现代化;- 函数组件上的
defaultProps:改用 ES6 默认参数; - 无初始值的
useRef():补null。
行为变化(影响测试断言)
- StrictMode 不再双调用 effect(影响测试中的 spy 调用次数断言);
propTypes运行时校验被移除(保留用于文档与 IDE,但不再产生运行时检查)。
迁移前置条件与升级路径
该插件假定目标代码库从 React 18 起步。如果你的项目还在 React 16/17,官方给出的路径是:先使用 react18-upgrade 插件(见 plugins/react18-upgrade/README.md)升级到 React 18.3.1,再使用本插件完成 React 19 的最终升级。这一前置条件也解释了为何整套管线严格围绕 React 18 → 19 的差异面设计——react@19 与 react-dom@19 的安装、RTL 16+ 的强制要求、createRoot 的既有正确性校验均以"已处于 React 18 生态"为前提。
关键特性总结
- 覆盖 8 类以上已移除 React API 的系统性清理;
- 处理复杂模式:Legacy Context、
forwardRef、defaultProps、字符串 ref; - 基于内存的可恢复管线:中断后可无缝续跑,不重复已完成阶段;
- 对不完整迁移零容忍:必须构建通过 + 测试全绿才宣告完成;
- StrictMode 感知的测试修复(实测计数而非猜测);
- Testing-library v16+ 兼容性验证;
- 错误边界与异步测试模式更新。
该插件属于 awesome-copilot 社区仓库(MIT 许可),其完整定义可通过 插件元数据 与各 Agent/Skill 文档在仓库中进一步查阅。对正在规划 React 19 升级的团队而言,这套"审计 → 依赖 → 源码 → 测试"四阶段 + 门禁验证 + 内存续跑的组合,提供了一条可复制、可追踪、可验证的工程化迁移路径。
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 StartedRust4.21 K635- DDeepSeek-V4.1-FlashDeepSeek-V4.1-Flash 是一个多模态混合专家(MoE)模型,拥有 5520 亿骨干参数,并支持最多一百万 token 的上下文长度。该模型原生支持图像和文本输入,并以自回归方式生成文本Python60
jforgamejforgame是一个一站式游戏服务器开发框架。包含游戏服务器开发所需要的各种组件,比如网关,socket服务端与客户端,自定义高效消息编解码,游戏热更新,游戏通用工具等等。包含游戏服,跨服,匹配服,后台管理系统等实现,同时提供大量业务案例以供学习。亦可用于其他socket应用,例如及时聊天等。Java131
fizz-gateway-nodeAn Aggregation API Gateway in Java . FizzGate 是一个基于 Java开发的微服务聚合网关,是拥有自主知识产权的应用网关国产化替代方案,能够实现热服务编排聚合、自动授权选择、线上服务脚本编码、在线测试、高性能路由、API审核管理、回调管理等目的,拥有强大的自定义插件系统可以自行扩展,并且提供友好的图形化配置界面,能够快速帮助企业进行API服务治理、减少中间层胶水代码以及降低编码投入、提高 API 服务的稳定性和安全性。Java80
certd开源SSL证书管理工具;全自动证书申请、更新、续期;通配符证书,泛域名证书申请;证书自动化部署到阿里云、腾讯云、主机、群晖、宝塔;https证书,pfx证书,der证书,TLS证书,nginx证书自动续签自动部署JavaScript90
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python290