Babel Plugin for React Compiler
The `babel-plugin-react-compiler` package, currently at version `1.0.0`, is a core component for integrating the React Compiler (codenamed "Forget") into JavaScript projects. Its primary function is to automatically memoize React components and hook calls at compile-time, aiming to eliminate unnecessary re-renders and significantly improve application performance without requiring manual `useMemo` or `useCallback` optimizations. This plugin is developed as part of the broader React ecosystem by Facebook/Meta, closely tied to the React core libraries, particularly with the release of React 19. While the plugin itself is at an initial `1.0.0` stable release, the underlying React Compiler is an actively evolving project, receiving continuous updates and refinements alongside major React versions. Its release cadence is therefore coupled with the React framework's development cycle, which often sees patch releases for bug fixes and performance improvements, with feature updates aligning with major React releases. This compiler is a key differentiator for React, promising "zero-cost" memoization for developers.
Common errors
-
Error: Plugin 'babel-plugin-react-compiler' not found.
cause The package `babel-plugin-react-compiler` is either not installed or its name is misspelled in the Babel configuration.fixInstall the package using `npm install --save-dev babel-plugin-react-compiler` or `yarn add --dev babel-plugin-react-compiler`. Verify the plugin name in your `babel.config.js` or `.babelrc`. -
TypeError: 'plugins' must be an array of arrays or strings.
cause When providing options to a Babel plugin, the plugin name and its options object must be enclosed within an inner array, e.g., `[['plugin-name', { options }]]`.fixCorrect the Babel configuration to wrap the plugin name and options in an inner array: `plugins: [['babel-plugin-react-compiler', { /* options */ }]]`. -
Unexpected component re-renders or incorrect memoization behavior after enabling the compiler.
cause This can occur due to subtle conflicts with existing manual `useMemo` / `useCallback` or violations of the Rules of React that the compiler now exposes.fixReview components for redundant manual memoization and consider removing them. Utilize `eslint-plugin-react-compiler` to identify and fix code patterns preventing optimal compiler functioning. -
Cannot find module 'react-compiler-runtime'
cause This error occurs when the `react-compiler-runtime` package is required but not installed, typically when targeting React versions older than 19 or within a library.fixInstall `react-compiler-runtime` as a direct dependency: `npm install react-compiler-runtime` or `yarn add react-compiler-runtime`. Ensure your bundler includes it in the output.
Warnings
- breaking The React Compiler is designed to largely replace manual memoization (`useMemo`, `useCallback`, `React.memo`). While it can coexist with existing manual memoization, completely removing existing manual memoization should be done cautiously, as it can subtly change compilation output and behavior.
- gotcha The `babel-plugin-react-compiler` must be the first plugin in your Babel plugin pipeline. If other transformation plugins run before it, the compiler may not receive the original source information needed for proper analysis and optimization, leading to unexpected behavior or skipped optimizations.
- gotcha While the React Compiler supports React versions 17 and 18, it is explicitly designed to work best with React 19. Using it with older React versions might require additional configuration, specifically installing `react-compiler-runtime` as a direct dependency and configuring a `target` option.
- gotcha The compiler introduces stricter adherence to the 'Rules of React'. It includes an ESLint rule (`eslint-plugin-react-compiler`) that identifies code patterns preventing optimization, such as mutating props or reading refs during render. Violations will cause the compiler to skip optimization for affected components.
- gotcha Initial integration of the compiler might modestly increase build times due to the new analysis and optimization step. While optimized runtime performance is the goal, the build process adds a new layer.
Install
-
npm install babel-plugin-react-compiler -
yarn add babel-plugin-react-compiler -
pnpm add babel-plugin-react-compiler
Imports
- Babel Plugin Configuration (Basic)
import { ReactCompilerPlugin } from 'babel-plugin-react-compiler'plugins: ['babel-plugin-react-compiler']
- Babel Plugin Configuration (With Options)
plugins: ['babel-plugin-react-compiler', { /* options */ }]plugins: [['babel-plugin-react-compiler', { /* options */ }]] - Babel Plugin in Vite (using @vitejs/plugin-react)
plugins: ['babel-plugin-react-compiler'] // directly in defineConfig plugins array for Vite
import { defineConfig } from 'vite'; import react from '@vitejs/plugin-react'; export default defineConfig({ plugins: [ react({ babel: { plugins: ['babel-plugin-react-compiler'], // must run first! }, }), ], });
Quickstart
/* babel.config.js */
module.exports = {
presets: ['@babel/preset-env', '@babel/preset-react'],
plugins: [
// The React Compiler plugin must run first in the Babel plugin pipeline.
'babel-plugin-react-compiler',
// ... other Babel plugins (e.g., for TypeScript, JSX transform)
],
};
/* src/App.js */
import { useState } from 'react';
function Header() {
console.log('Header re-rendered');
return <h1>React Compiler Demo</h1>;
}
export default function App() {
const [count, setCount] = useState(0);
// With React Compiler, Header should not re-render when count changes
// unless its props change or it's forced to.
return (
<div>
<Header />
<p>Count: {count}</p>
<button onClick={() => setCount(c => c + 1)}>
Increment
</button>
<ExpensiveCalculation value={count} />
</div>
);
}
function ExpensiveCalculation({ value }) {
// Simulate an expensive computation that the compiler might memoize
let result = 0;
for (let i = 0; i < 1_000_000; i++) {
result += Math.sqrt(i) * value;
}
console.log('ExpensiveCalculation re-rendered with value:', value);
return <p>Expensive Result: {result.toFixed(2)}</p>;
}