在今年 5 月份的 React Conf 2024 上,React 团队宣布推出 React Compiler 的实验版本。

经过几个月的迭代和优化,React 团队修复了 React 社区报告的大量 Bug,收到了几个高质量的 Bug 修复和对编译器的 PR ,使编译器更能适应各种 JavaScript 模式,并继续在 Meta 内部更广泛地落地编译器。

React 官方近日发布了 React Compiler 的 Beta 版,并且宣布将于不久后发布 RC 版本,这也标志着 React Compiler 即将进入稳定阶段了。现在可以通过可选的 React-compiler-runtime 包正式支持 React 17+ 上的应用程序的 React Compiler。
什么是 React Compiler?
React Compiler 是一个全新的编译器,旨在编译时自动优化我们的 React 应用。它可以与原生 JavaScript 一起工作,并且理解 React 的规则,因此使用它时不需要重写任何代码。
自动优化
React Compiler 可以帮我们自动完成代码的记忆化(memoization),这意味着它会自动记住哪些组件或钩子(hooks)需要重新渲染,从而提高性能。当检测到违反 React 规则的情况时,它会自动跳过这些有问题的部分,但继续安全地编译其它代码。例如,以下代码展示了 React Compiler 如何处理组件的重新渲染,在以下示例中,每当 friends 的状态发生变化时,都会重新渲染 <MessageButton>:
function FriendList({ friends }) {
const onlineCount = useFriendOnlineCount();
if (friends.length === 0) {
return <NoFriends />;
}
return (
<div>
<span>{onlineCount} online</span>
{friends.map((friend) => (
<FriendListCard key={friend.id} friend={friend} />
))}
<MessageButton />
</div>
);
}
React Compiler 自动应用相当于手动记忆的功能,确保只有应用程序的相关部分随着状态变化而重新渲染,这有时也被称为叫 “细粒度响应式”。在上面的示例中,React Compiler 确定即使 friends 发生变化,<FriendListCard /> 的返回值也可以复用,并且可以避免重新创建此 JSX 并避免在计数变化时重新渲染 <MessageButton>。
复杂计算优化
React Compiler 还能自动记忆化一些复杂计算。例如:
// 此函数并不会被 React Compiler 记忆化,因为它不是组件或钩子
function expensivelyProcessAReallyLargeArrayOfObjects() { /* ... */ }
// 堆代码 duidaima.com
// 这个函数会被 React Compiler 记忆化
function TableContainer({ items }) {
const data = expensivelyProcessAReallyLargeArrayOfObjects(items);
// ...
}
不过,如果 expensivelyProcessAReallyLargeArrayOfObjects 是一个真正耗时的函数,你可能需要考虑在 React 外部实现它的记忆化。
安装 React Compiler
要试用 React Compiler,可以在 React 17+ 的应用和库中安装 Beta 版:
npm install -D babel-plugin-react-compiler@beta eslint-plugin-react-compiler@beta
或者使用 Yarn:
yarn add -D babel-plugin-react-compiler@beta eslint-plugin-react-compiler@beta
使用 Babel
安装 Babel 插件:
npm install babel-plugin-react-compiler@beta
然后在 Babel 配置中添加插件,确保编译器先运行:
const ReactCompilerConfig = { /* ... */ };
module.exports = function () {
return {
plugins: [
['babel-plugin-react-compiler', ReactCompilerConfig], // 必须先运行!
],
};
};
其他工具链
在不同的工具链中,我们也可以随着文档进行配置,如 Vite、Next.js、Remix、Webpack、Expo 等。
如果你使用 Vite,你可以将插件添加到 vite-plugin-react:
// vite.config.js
const ReactCompilerConfig = { /* ... */ };
export default defineConfig(() => {
return {
plugins: [
react({
babel: {
plugins: [
["babel-plugin-react-compiler", ReactCompilerConfig],
],
},
}),
],
// ...
};
});
Next.js:在 next.config.js 添加 experimental.reactCompiler 选项 :
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
experimental: {
reactCompiler: true,
},
}
export default nextConfig
Remix:
// vite.config.js
import babel from "vite-plugin-babel";
const ReactCompilerConfig = { /* ... */ };
export default defineConfig({
plugins: [
remix({ /* ... */}),
babel({
filter: /\.[jt]sx?$/,
babelConfig: {
presets: ["@babel/preset-typescript"], // if you use TypeScript
plugins: [
["babel-plugin-react-compiler", ReactCompilerConfig],
],
},
}),
],
});
Webpack/Rspack:
// webpack.config.js / rspack.config.js
// You can leverage your IDE's Intellisense (autocompletion, type check, etc.) with the helper function `defineReactCompilerLoaderOption`:
const { defineReactCompilerLoaderOption, reactCompilerLoader } = require('react-compiler-webpack');
module.exports = {
module: {
rules: [
rules: [
{
test: /\.[mc]?[jt]sx$/i,
exclude: /node_modules/,
use: [
// babel-loader, swc-loader, esbuild-loader, or anything you like to transpile JSX should go here.
// If you are using rspack, the rspack's buiilt-in react transformation is sufficient.
// { loader: 'swc-loader' },
// Now add forgetti-loader
{
loader: reactCompilerLoader,
options: defineReactCompilerLoaderOption({
// React Compiler options goes here
})
}
]
}
]
]
}
};
在不同项目中的应用
现有项目
对于现有项目,可以先在小目录中运行编译器,逐步扩展覆盖范围:
const ReactCompilerConfig = {
sources: (filename) => {
return filename.indexOf('src/path/to/dir') !== -1;
},
};
新项目
对于新项目,可以在整个代码库上启用编译器,这是默认行为。
在库中的使用
最初发布的 React Compiler 专注于在应用程序中使用编译器,已经收到了大量的反馈,并且对编译器进行了显著改进。现在,React 团队准备广泛接受社区反馈,并邀请库的作者尝试编译器,以提高性能和开发者体验。
由于 React Compiler 需要在任何代码转换之前运行,因此无法通过应用程序的构建流程编译所使用的库。我们的建议是库的维护者独立编译测试他们的库,并将编译后的代码提交到 npm 上。因为代码是预先编译的,库的用户无需启用编译器,就可以享受到自动记忆化带来的性能提升。
向后兼容性
尽管理论上 React Compiler 生成的代码依赖于 React 19 版本,但官方已经扩展支持 React 17 和 React 18。在 React 19 之前的版本上使用编译器,需要安装 react-compiler-runtime 包:
npm install react-compiler-runtime@beta
并在 Babel 配置中添加相应的 target:
const ReactCompilerConfig = {
target: '18' // 支持 '17' | '18' | '19'
};
module.exports = function () {
return {
plugins: [
['babel-plugin-react-compiler', ReactCompilerConfig],
],
};
};
问题排查
当开发遇到问题时,我们可以通过 React Compiler Playground 创建一个最小的复现例子,并在 facebook/react 提交 Issues。同时,React Compiler 的 ESLint 插件可帮助开发人员主动识别和纠正 React 规则违规。我们强烈建议大家立即使用 linter。linter 不需要我们安装编译器,因此即使我们尚未准备好试用编译器,也可以独立使用它。
npm install -D eslint-plugin-react-compiler@beta
然后将其添加到你的 ESLint 配置中:
import reactCompiler from 'eslint-plugin-react-compiler'
export default [
{
plugins: {
'react-compiler': reactCompiler,
},
rules: {
'react-compiler/react-compiler': 'error',
},
},
];
React Compiler 在 Meta 的应用
在 React Conf 大会上,React 团队分享了在 Quest Store 和 Instagram 上成功部署 React Compiler 的经验。自那以后,React 团队又在 Meta 的多个主要 Web 应用上部署了 React Compiler,包括 Facebook 和 Threads。这意味着,如果我们最近使用了这些应用程序,使用体验可能已经由 React Compiler 提供支持。够在一个包含超过 100,000 个 React 组件的单一代码仓库中,几乎不需要代码修改,就将这些应用程序迁移到了 React Compiler 上。
几乎在所有这些应用程序中都看到了显著的性能提升。尤其是在已经被 Meta 工程师和 React 专家多年来精心调优和优化的应用程序中,即便是几个百分点的提升也已是巨大的胜利。
另外, React Compiler 也能够提升开发者的生产力。为了衡量这一点,React 团队与 Meta 数据科学团队合作,进行了手动记忆化对生产力影响的深入统计分析。在 Meta 推出编译器之前,我们发现只有大约 8% 的 React 合并请求使用了手动记忆化,而这些合并请求的撰写时间平均长 31-46%。这证实了我们普遍的直觉:手动记忆化带来了认知负担,我们期望 React Compiler 将带来更高效的代码撰写和审核体验。值得注意的是,React Compiler 默认确保所有代码都进行记忆化,而不仅仅是(案例中)8% 的显式记忆化代码。
未来计划
以下是目前的 Roadmap,可能未来也会有所变动。
React 团队的计划是在 Beta 版本发布后不久,发布编译器的候选版本(Release Candidate),当大多数遵循 React 规则的应用和库都能很好地与编译器配合使用后再发布。在社区提供最后反馈的一段时间之后,发布编译器的稳定版本。稳定版本的发布将标志着 React 开始新基础的起点,所有应用程序和库都将被强烈推荐使用编译器及其 ESLint 插件。
✅ 实验版本:于 2024 年 React Conf 大会上发布,主要面向早期采纳者提供反馈。
✅ 公共 Beta:现已发布,面向更广泛社区提供反馈。
🚧 候选版本:React Compiler 能无问题地支持大多数遵循规则的应用和库。
🚧 全面可用(General Availability):在社区反馈期过后发布。
这些版本还包括编译器的 ESLint 插件,该插件通过静态分析提供诊断信息。React 团队计划将现有的 eslint-plugin-react-hooks 插件与编译器的 ESLint 插件合并,这样只需要安装一个插件。
在稳定版本之后,React 团队计划添加更多的编译器优化和改进。这包括自动记忆化的持续改进和全新的优化,而且几乎不需要变动产品代码。每次编译器的新版本升级都将十分简便,并且会持续提升性能,增强对多样化 JavaScript 和 React 模式的处理。在整个过程中,React 团队还计划为 React 制作一个 IDE 扩展。这仍然处于非常早期的研究阶段。
开放 React Compiler 工作组
在此前 React Conf 大会上宣布了邀请制的 React Compiler 工作组,旨在为编译器的实验版本提供反馈、解答问题并进行合作。

今天,随着 React Compiler 的 Beta 版本发布,React 团队决定将工作组的成员资格向所有人开放。React Compiler 工作组的目标是为现有应用和库逐步顺利地引入 React Compiler 做准备。
参考:
https://github.com/reactwg/react-compiler
https://react.dev/blog/2024/10/21/react-compiler-beta-release
https://react.dev/learn/react-compiler