Skip to main content

Babel Plugin

The babel-plugin-react-compiler package is the primary interface for transforming React code with automatic memoization.

Installation

npm install --save-dev babel-plugin-react-compiler

Basic Setup

Babel Configuration

module.exports = {
  presets: ['@babel/preset-react'],
  plugins: [
    'babel-plugin-react-compiler',
  ],
};

Plugin Options

Pass configuration options as the second element in the plugin array:
babel.config.js
module.exports = {
  plugins: [
    [
      'babel-plugin-react-compiler',
      {
        // Options here
        environment: {
          validateHooksUsage: true,
          enablePreserveExistingMemoizationGuarantees: true,
        },
      },
    ],
  ],
};

Option Structure

interface PluginOptions {
  // Environment configuration (compiler behavior)
  environment?: EnvironmentConfig;
  
  // Logging interface
  logger?: Logger;
  
  // Compilation mode
  mode?: 'all_features' | 'no_inferred_memo';
  
  // Opt-in/opt-out configuration
  sources?: (filename: string) => 'all' | 'none' | 'opt-in' | 'opt-out';
  
  // Enable Reanimated integration check
  enableReanimatedCheck?: boolean;
}

Compilation Modes

Compile All Components

By default, the compiler attempts to compile all components and hooks:
module.exports = {
  plugins: [
    'babel-plugin-react-compiler',
  ],
};

Opt-In Mode

Only compile components with "use memo" directive:
babel.config.js
module.exports = {
  plugins: [
    [
      'babel-plugin-react-compiler',
      {
        sources: (filename) => {
          // Opt-in for specific directories
          if (filename.includes('src/components')) {
            return 'opt-in';
          }
          return 'none';
        },
      },
    ],
  ],
};
Mark components for compilation:
function MyComponent(props) {
  'use memo';
  // Component code
}

Opt-Out Mode

Compile everything except components with "use no memo" directive:
babel.config.js
module.exports = {
  plugins: [
    [
      'babel-plugin-react-compiler',
      {
        sources: (filename) => {
          return 'opt-out';
        },
      },
    ],
  ],
};
Skip specific components:
function ProblematicComponent(props) {
  'use no memo';
  // Component code that shouldn't be compiled
}

File-Based Configuration

babel.config.js
module.exports = {
  plugins: [
    [
      'babel-plugin-react-compiler',
      {
        sources: (filename) => {
          // Don't compile test files
          if (filename.includes('__tests__')) {
            return 'none';
          }
          
          // Opt-in for new features
          if (filename.includes('src/features/new')) {
            return 'opt-in';
          }
          
          // Opt-out for legacy code
          if (filename.includes('src/legacy')) {
            return 'opt-out';
          }
          
          // Compile all others
          return 'all';
        },
      },
    ],
  ],
};

Build Tool Integration

Webpack

Integrate with babel-loader:
webpack.config.js
module.exports = {
  module: {
    rules: [
      {
        test: /\.(js|jsx|ts|tsx)$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: [
              '@babel/preset-react',
              '@babel/preset-typescript',
            ],
            plugins: [
              [
                'babel-plugin-react-compiler',
                {
                  environment: {
                    validateHooksUsage: true,
                  },
                },
              ],
            ],
            cacheDirectory: true, // Enable caching
          },
        },
      },
    ],
  },
};

Vite

Configure with @vitejs/plugin-react:
vite.config.js
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';

export default defineConfig({
  plugins: [
    react({
      babel: {
        plugins: [
          [
            'babel-plugin-react-compiler',
            {
              environment: {
                enableOptionalDependencies: true,
              },
            },
          ],
        ],
      },
    }),
  ],
});

Next.js

Next.js 13.5+ has built-in support:
next.config.js
const nextConfig = {
  experimental: {
    reactCompiler: {
      // Compiler options
      enablePreserveExistingMemoizationGuarantees: true,
    },
  },
};

module.exports = nextConfig;
For older versions, use custom Babel config:
.babelrc
{
  "presets": ["next/babel"],
  "plugins": [
    [
      "babel-plugin-react-compiler",
      {
        // options
      }
    ]
  ]
}

Create React App

Use react-app-rewired or craco:
module.exports = {
  babel: {
    plugins: [
      [
        'babel-plugin-react-compiler',
        {
          environment: {
            validateHooksUsage: true,
          },
        },
      ],
    ],
  },
};

Rollup

Use with @rollup/plugin-babel:
rollup.config.js
import babel from '@rollup/plugin-babel';

export default {
  plugins: [
    babel({
      babelHelpers: 'bundled',
      presets: ['@babel/preset-react'],
      plugins: [
        [
          'babel-plugin-react-compiler',
          {
            // options
          },
        ],
      ],
    }),
  ],
};

esbuild

Use with esbuild-plugin-babel:
build.js
const esbuild = require('esbuild');
const babel = require('esbuild-plugin-babel');

esbuild.build({
  entryPoints: ['src/index.jsx'],
  bundle: true,
  outfile: 'dist/bundle.js',
  plugins: [
    babel({
      filter: /\.(js|jsx|ts|tsx)$/,
      config: {
        presets: ['@babel/preset-react'],
        plugins: ['babel-plugin-react-compiler'],
      },
    }),
  ],
});

Custom Logger

Implement custom logging for compiler events:
babel.config.js
class CustomLogger {
  logEvent(filename, event) {
    if (event.kind === 'CompileSuccess') {
      console.log(`✓ Compiled: ${event.fnName} in ${filename}`);
    } else if (event.kind === 'CompileError') {
      console.error(`✗ Error in ${filename}:`, event.error);
    }
  }
  
  debugLogIRs(value) {
    // Log intermediate representations
    if (value.kind === 'hir') {
      console.log('HIR:', value.name);
    }
  }
}

module.exports = {
  plugins: [
    [
      'babel-plugin-react-compiler',
      {
        logger: new CustomLogger(),
      },
    ],
  ],
};

Logger Interface

interface Logger {
  // Called for each compilation event
  logEvent(filename: string | null, event: LogEvent): void;
  
  // Called for debug output (when enabled)
  debugLogIRs?(value: CompilerPipelineValue): void;
}

type LogEvent =
  | { kind: 'CompileSuccess'; fnName: string; fnLoc: SourceLocation }
  | { kind: 'CompileError'; fnName: string | null; error: CompilerError }
  | { kind: 'CompileDiagnostic'; fnName: string; diagnostic: string }
  | { kind: 'Timing'; measurement: PerformanceMeasure };

Performance Optimization

Enable Caching

webpack.config.js
module.exports = {
  module: {
    rules: [
      {
        test: /\.jsx?$/,
        use: {
          loader: 'babel-loader',
          options: {
            cacheDirectory: true,
            cacheCompression: false,
          },
        },
      },
    ],
  },
};

Exclude node_modules

{
  test: /\.(js|jsx)$/,
  exclude: /node_modules/,
  use: 'babel-loader',
}

Parallel Processing

Use thread-loader for parallel compilation:
webpack.config.js
module.exports = {
  module: {
    rules: [
      {
        test: /\.jsx?$/,
        exclude: /node_modules/,
        use: [
          'thread-loader',
          {
            loader: 'babel-loader',
            options: {
              plugins: ['babel-plugin-react-compiler'],
              cacheDirectory: true,
            },
          },
        ],
      },
    ],
  },
};

TypeScript Support

The plugin works seamlessly with TypeScript:
babel.config.js
module.exports = {
  presets: [
    '@babel/preset-typescript',
    '@babel/preset-react',
  ],
  plugins: [
    'babel-plugin-react-compiler',
  ],
};

TSX Files

webpack.config.js
module.exports = {
  module: {
    rules: [
      {
        test: /\.(ts|tsx)$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: [
              '@babel/preset-typescript',
              '@babel/preset-react',
            ],
            plugins: ['babel-plugin-react-compiler'],
          },
        },
      },
    ],
  },
};

Debugging

Enable Compiler Timing

ENABLE_REACT_COMPILER_TIMINGS=1 npm run build

Debug Output

Implement debugLogIRs in your logger:
class DebugLogger {
  debugLogIRs(value) {
    console.log(`[${value.kind}] ${value.name}`);
    if (value.kind === 'hir') {
      console.log(prettyPrintHIR(value.value));
    }
  }
}

Source Maps

Ensure source maps are enabled:
webpack.config.js
module.exports = {
  devtool: 'source-map',
  module: {
    rules: [
      {
        test: /\.jsx?$/,
        use: {
          loader: 'babel-loader',
          options: {
            sourceMaps: true,
          },
        },
      },
    ],
  },
};

Troubleshooting

Plugin Order

React Compiler should run early in the plugin chain:
module.exports = {
  plugins: [
    'babel-plugin-react-compiler', // First
    '@babel/plugin-transform-runtime',
    // Other plugins...
  ],
};

Conflicting Transforms

Avoid transforms that modify React code structure:
// ✗ Bad - may conflict
plugins: [
  'babel-plugin-react-compiler',
  'some-jsx-transform', // May conflict
]

// ✓ Good
plugins: [
  'babel-plugin-react-compiler',
  // Non-React transforms
]

Memory Issues

For large codebases, increase Node memory:
package.json
{
  "scripts": {
    "build": "NODE_OPTIONS='--max-old-space-size=4096' webpack"
  }
}

Next Steps

Configuration

Detailed configuration options

ESLint Plugin

Set up React rules validation

How It Works

Understanding the compilation process

Contributing

Contribute to React Compiler

Build docs developers (and LLMs) love