Instatic React Compiler Configuration: Complete Setup and Manual Memoization Ban
Instatic enables the React Compiler across the entire application via Vite configuration, automatically memoizing components and hooks so that manual memoization (useMemo, useCallback, React.memo) is prohibited except for three specific escape hatches.
The Instatic React Compiler configuration eliminates manual performance optimization by leveraging automatic memoization at the build level. This architecture, implemented in the CoreBunch/Instatic repository, shifts memoization responsibility from developers to the compiler and enforces strict standards through ESLint. Understanding this setup is essential for contributing to the Instatic React codebase.
Enabling the Compiler in Vite
The compiler activation resides in [vite.config.ts](https://github.com/CoreBunch/Instatic/blob/main/vite.config.ts), where the Babel preset integrates with the Vite plugin pipeline.
Vite Plugin Setup
The configuration imports reactCompilerPreset from @vitejs/plugin-react and applies it via @rolldown/plugin-babel:
import react, { reactCompilerPreset } from '@vitejs/plugin-react';
import babel from '@rolldown/plugin-babel';
export default defineConfig({
plugins: [
react(),
babel({ presets: [reactCompilerPreset()] }),
],
});
This setup applies the React Compiler to the entire application, transforming eligible functions during the Babel compilation phase.
Compilation Mode and Scope
The compiler runs in infer mode, which is the default setting. In this mode, the compiler processes only functions that match specific patterns:
- Components: Functions with UpperCamelCase names that return JSX
- Hooks: Functions with
useFoonaming conventions
Utilities, router helpers, and Zustand selectors remain untouched, preventing unwanted useMemoCache insertions that previously violated the Rules of Hooks.
The Manual Memoization Ban
Because the React Compiler provides automatic memoization for all eligible functions, manual memoization utilities add no performance benefit. According to [docs/reference/react-compiler.md](https://github.com/CoreBunch/Instatic/blob/main/docs/reference/react-compiler.md), these patterns create code clutter and maintenance overhead without improving performance.
Three Permitted Exceptions
The project enforces a strict ban with exactly three escape hatches:
- Functions used in hook dependency arrays – When a function serves as a dependency for
useEffector similar hooks,useCallbackis required to maintain stable reference identity. React.memofor hot, list-rendered components – Performance-critical recursive renderers, such as large tree views, may useReact.memowhere the compiler's automatic memoization proves insufficient.- Compiler escape-hatches – When the compiler cannot safely analyze a function, the file must include the
"use no memo"directive or an appropriate ESLint disable comment.
ESLint Enforcement Configuration
The ban is codified in [eslint.config.js](https://github.com/CoreBunch/Instatic/blob/main/eslint.config.js), which integrates two specific plugins:
import reactCompiler from 'eslint-plugin-react-compiler';
import reactHooks from 'eslint-plugin-react-hooks';
export default defineConfig([
{
files: ['**/*.{ts,tsx}'],
extends: [
reactHooks.configs.flat.recommended,
reactCompiler.configs.recommended,
],
},
]);
Key enforcement mechanisms:
eslint-plugin-react-compileridentifies functions the compiler cannot safely memoize.eslint-plugin-react-hookscatches legitimate cases requiring stable identities throughexhaustive-depsandrefsrules.
Implementation Examples
Standard Component Pattern
Components should remain plain functions without memoization wrappers. In src/ui/components/Button/Button.tsx:
export function Button({ label }: { label: string }) {
// Compiler handles memoization automatically
return <button>{label}</button>;
}
Exception 1: Stable Callback for Effects
When a function is used in a dependency array, apply useCallback:
export function SearchBox() {
const [query, setQuery] = useState('');
const fetchResults = useCallback(() => {
// Fetch logic here
}, []);
useEffect(() => {
fetchResults();
}, [fetchResults]);
return <input value={query} onChange={e => setQuery(e.target.value)} />;
}
Exception 2: Heavy List Rendering
For performance-critical recursive renders, React.memo is permitted. In src/admin/pages/site/ui/Tree/NodeRenderer.tsx:
import { memo } from 'react';
export const NodeRenderer = memo(function NodeRenderer({ node }) {
return <div>{node.title}</div>;
});
Exception 3: Compiler Escape Hatch
When the compiler cannot process complex logic, disable it for that file:
"use no memo";
export function complexAlgorithm(data: number[]) {
// Complex logic the compiler cannot analyze
return data.map(/* ... */);
}
Summary
- The Instatic React Compiler configuration activates automatic memoization via
vite.config.tsusingreactCompilerPreset()and@rolldown/plugin-babel. - The compiler runs in infer mode, processing only component and hook functions while ignoring utilities.
- Manual memoization is banned because the compiler provides equivalent performance benefits without code clutter.
- Three exceptions exist: hook dependency callbacks,
React.memofor hot list renders, and files with the"use no memo"directive. - ESLint enforcement in
eslint.config.jscombineseslint-plugin-react-compilerandeslint-plugin-react-hooksto maintain these rules.
Frequently Asked Questions
What happens if I use useMemo in Instatic?
The ESLint configuration will flag unnecessary manual memoization. Since the React Compiler automatically memoizes all eligible functions, useMemo provides no additional benefit and violates the project's coding standards unless it falls under one of the three documented exceptions.
How do I know if the React Compiler is processing my component?
The compiler targets functions with UpperCamelCase names returning JSX (components) or functions starting with use (hooks). If your function follows these patterns in vite.config.ts, it is being compiled. The eslint-plugin-react-compiler will alert you if it encounters functions it cannot safely memoize.
Can I disable the React Compiler for specific files?
Yes. Add the "use no memo" directive at the top of the file. This escape hatch tells the compiler to skip memoization for that module, which is useful for complex algorithms or edge cases the compiler cannot analyze. You should also document the reason with an ESLint disable comment if necessary.
Why does Instatic use @rolldown/plugin-babel instead of standard Vite React plugins?
The @rolldown/plugin-babel package is required to inject the reactCompilerPreset() into the build pipeline. While @vitejs/plugin-react provides the preset export, the Babel plugin from Rolldown enables the specific compiler configuration needed for the automatic memoization setup in this project.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →