React Compiler — это инструмент этапа сборки, который анализирует код компонентов и автоматически вставляет мемоизацию (useMemo, useCallback, React.memo) без участия разработчика. Он работает с React 17+, прошёл боевое крещение в продуктах Meta и, по данным замеров, сокращает время рендеринга на 20–30%, ускоряет начальную загрузку до 12% и ускоряет взаимодействия до 2,5 раз. Стабильный релиз состоялся в октябре 2025 года, и теперь интеграция с Next.js, Vite и Expo доступна из коробки.

Что такое React Compiler и почему он меняет правила игры
Десятилетие инженерной эволюции уместилось в один Babel-плагин. React Compiler (ранее известный как React Forget) — это оптимизирующий компилятор, который на этапе сборки анализирует ваши компоненты и хуки, а затем автоматически добавляет мемоизацию — ровно туда, где она действительно нужна. Разработчику больше не нужно вручную расставлять useMemo, useCallback и React.memo — компилятор делает это точнее, чем человек, и охватывает такие случаи (условные пути, замыкания), которые при ручной оптимизации легко пропустить.
Философия проста: вместо «подсказок» времени исполнения, которые React может проигнорировать (да, useMemo — всего лишь рекомендация, а не гарантия), компилятор гарантирует мемоизацию на уровне выражений, а не целых хуков. Это фундаментальный сдвиг: раньше разработчик угадывал, где нужна оптимизация; теперь компилятор знает, потому что прослеживает потоки данных через все пути рендеринга.
Как это работает: от AST до HIR — архитектура компилятора
React Compiler реализован как Babel-плагин (babel-plugin-react-compiler@1.0.0), но его ядро не зависит от Babel. Он получает на вход AST (абстрактное синтаксическое дерево), преобразует его в собственное внутреннее представление — HIR (High-Level Intermediate Representation), основанное на графе потока управления (Control Flow Graph).
Зачем нужен HIR? Традиционное AST описывает только синтаксис — «как выглядит код». CFG/HIR описывает логику исполнения: какие пути возможны, где данные создаются, где мутируют, где используются. Это позволяет компилятору точно определить, какие значения можно безопасно кешировать, не боясь нарушить корректность.
После построения HIR компилятор выполняет несколько проходов:
- Анализ потока данных — прослеживает, какие переменные зависят от каких props или state.
- Анализ мутабельности — определяет, какие значения изменяются между рендерами, а какие стабильны.
- Вставка гранулярной мемоизации — компилятор кеширует не весь компонент, а отдельные выражения. Выходной код использует внутренний runtime-механизм
_c()(слот-кеш изreact-compiler-runtime).
Посмотрим, как выглядит работа компилятора на практике:
// Исходный код (React 19, без ручной мемоизации)
function TodoList({ items, filter }) {
const visible = items.filter(i => i.tag === filter);
const onClick = (id) => toggle(id);
return <List items={visible} onClick={onClick} />;
}После обработки React Compiler (v1.0) скомпилированный код концептуально выглядит так:
// Компилированный вывод (упрощённая схема)
function TodoList({ items, filter }) {
const $ = _c(4);
let visible;
if ($[0] !== items || $[1] !== filter) {
visible = items.filter(i => i.tag === filter);
$[0] = items;
$[1] = filter;
$[2] = visible;
} else {
visible = $[2];
}
// onClick и JSX кешируются аналогично
// ...
}Компилятор не просто «заворачивает всё в useMemo» — он кеширует каждое выражение с точностью до отдельных переменных. Такой гранулярности практически невозможно достичь ручной мемоизацией на большой кодовой базе.
Что происходит с useMemo, useCallback и React.memo?
Короткий ответ: они становятся не нужны в повседневной практике. В блоге React 1.0 прямо указано: «Мы не ожидаем, что разработчикам придётся вручную использовать useMemo, useCallback или React.memo для производительности». Компилятор применяет эквивалентные оптимизации автоматически.
Однако есть нюансы:
- React.memo всё ещё нужен для кастомных сравнений. Если вам нужна глубокая проверка пропсов (например, сравнение по определённым полям объекта), компилятор не предоставляет такой возможности — здесь ручное управление сохраняется.
- Хуки остаются в коде для обратной совместимости. Существующий код с useMemo продолжит работать. Компилятор не удаляет ваши ручные мемоизации, а дополняет их. Можно постепенно вычищать ручную оптимизацию.
- Классовые компоненты не поддерживаются — компилятор работает только с функциональными компонентами и хуками.
Как включить React Compiler в проект: пошаговая инструкция
React 19 (нативная поддержка)
React 19 включает runtime компилятора из коробки — react-compiler-runtime не нужен.
npm install --save-dev babel-plugin-react-compilerДобавьте плагин первым в списке Babel-плагинов:
// babel.config.js (React 19, версия компилятора 1.0.0)
module.exports = {
plugins: [
['babel-plugin-react-compiler', {
target: '19' // опционально, по умолчанию 19
}]
]
};React 17/18 (с дополнительным runtime)
npm install --save-dev babel-plugin-react-compiler
npm install react-compiler-runtime// babel.config.js (React 17/18)
module.exports = {
plugins: [
['babel-plugin-react-compiler', {
target: '18' // или '17'
}]
]
};Без пакета react-compiler-runtime скомпилированный код не запустится на версиях ниже 19.
Next.js (v15.3.1+ или v16)
Next.js включает оптимизацию на основе SWC, которая применяет компилятор только к файлам с JSX или хуками, что быстрее полного перебора Babel.
// next.config.ts (Next.js 15/16)
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
experimental: {
reactCompiler: true,
},
}
export default nextConfigДля версии Next.js 16 поддержка помечена как стабильная.
Vite (v6+ с @vitejs/plugin-react v6+)
Начиная с @vitejs/plugin-react v6, внутренний Babel заменён на oxc (Rust), поэтому Babel-плагины требуют отдельной обвязки через @rolldown/plugin-babel:
npm install --save-dev @vitejs/plugin-react @rolldown/plugin-babel babel-plugin-react-compiler// vite.config.js (Vite 8 + @vitejs/plugin-react v6)
import { defineConfig } from 'vite'
import react, { reactCompilerPreset } from '@vitejs/plugin-react'
import { babel } from '@rolldown/plugin-babel'
export default defineConfig({
plugins: [
babel({
include: /\.[jt]sx?$/,
babelConfig: reactCompilerPreset(),
}),
react(),
],
})Важен порядок: babel() должен идти перед react().
Постепенное внедрение с 'use memo'
Для больших проектов рекомендуется режим аннотаций (annotation mode) — компилятор обрабатывает только файлы с директивой 'use memo':
// babel.config.js
module.exports = {
plugins: [['babel-plugin-react-compiler', {
compilationMode: 'annotation'
}]]
}// Компонент, который будет оптимизирован
function ProductCard({ product }) {
'use memo';
// ...
}
// Этот компонент компилятор пропустит
function SimpleWrapper() {
// ...
}Реальные цифры: насколько быстрее с React Compiler
Данные из production-окружений и независимых тестов:
| Источник | Метрика | Улучшение |
| Meta Quest Store (внутренние данные Meta) | Начальная загрузка | до 12% быстрее |
| Meta Quest Store | Некоторые взаимодействия | в 2,5 раза быстрее |
| Sanity Studio (v3.65.0) | Время рендеринга/латентность | -20–30% (1231 из 1411 компонентов) |
| Wakelet (100% пользователей) | Largest Contentful Paint (LCP) | с 2.6 до 2.4 с (-10%) |
| Wakelet | Interaction to Next Paint (INP) | с 275 до 240 мс (-15%) |
| Wakelet (чистые React-компоненты) | INP | до -30% |
| Независимый тест (N. Makarevich, 15K строк) | Смешанные результаты | Зависит от проекта |
Результаты варьируются: прирост максимален на компонентах с глубокой вложенностью и частыми обновлениями, но минимален на простых формах. Компилятор не заменяет профилирование, а избавляет от систематической ручной мемоизации.
Ограничения и подводные камни
React Compiler не всесилен. Он пропускает компоненты, которые:
- Нарушают «Правила React» (мутируют состояние в рендере, используют
refне по назначению). - Содержат вызовы
setStateвнутри тела функции (компилятор не может гарантировать стабильность). - Используют несовместимые внешние библиотеки.
Компилятор проверяет ваш код с помощью ESLint-правил, встроенных в eslint-plugin-react-hooks (начиная с версии v5.6.2+, правило recommended-latest). Всего добавлено 18 новых правил, включая проверку чистоты (purity), иммутабельности, корректности refs и запрета setState в рендере. Прежде чем включать компилятор, стоит прогнать линтер и устранить предупреждения — это гарантирует, что максимум компонентов будет охвачен оптимизацией.
Ещё один нюанс: компилятор не делает виртуализацию, ленивую загрузку или оптимизацию бандла. Это ортогональные техники. Он решает только проблему избыточных ререндеров.
Будущее: куда движется React Compiler
Релиз 1.0 — только начало. Команда React уже работает над:
- SWC- и oxc-плагинами — чтобы уйти от зависимости от Babel и ускорить сборку.
- Более умным анализом зависимостей — поддержка опциональных цепочек, индексов массивов, а в перспективе — equality-проверок и строковой интерполяции.
- Компиляцией библиотек — чтобы авторы npm-пакетов могли поставлять уже скомпилированный код, снимая нагрузку с конечного разработчика.
В ближайшие годы React Compiler станет стандартом де-факто для всех новых проектов, а ручная мемоизация перейдёт в разряд нишевых техник для краевых случаев.