全面解析React Compiler Beta 版:突破创新,提升开发效率!
在今年 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() { /* ... */ } // 这个函数会被 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
做准备。
文章来源:code 秘密花园
码云笔记 » 全面解析React Compiler Beta 版:突破创新,提升开发效率!