Compiler Playground
Overview
The React Compiler Playground is an interactive web-based tool designed to help you understand how the compiler analyzes, optimizes, and transforms your React components. By providing real-time visualization of the compiler's internal passes, the playground serves as a powerful debugging utility for inspecting memoization behavior and identifying why specific code patterns may or may not be optimized.
Using the Playground
The playground interface is split into two primary sections: the Editor and the Output Inspector.
- Input Editor: Paste your React component or Hook code here. The compiler runs automatically as you type.
- Pass Selector: A dropdown or sidebar that allows you to toggle between different stages of the compilation process, from initial parsing to final JavaScript output.
- Output Pane: Displays the result of the selected compiler pass, including visual representations of reactive scopes and dependency arrays.
Understanding Compiler Passes
To effectively debug your components, you can inspect several key stages of the compilation pipeline:
- HIR (High-level Intermediate Representation): View the code after it has been desugared into a flat, instruction-based format. This is useful for seeing how the compiler interprets control flow and variable references.
- Reactive Scopes: This pass visualizes how the compiler groups instructions into memoization blocks. You can see which values are treated as "outputs" of a scope and which values are tracked as dependencies.
- Final Output: The transformed JavaScript code that will actually run in the browser. This includes the generated
useMemoCache(or similar runtime optimization) calls.
Debugging Memoization
The playground is the best way to understand the compiler's "Escape Analysis." For example, if a value is not being memoized, you can use the playground to determine if the compiler has flagged it as non-escaping.
Escaping vs. Non-Escaping Values
The compiler prunes reactive scopes for values that do not "escape" the component (i.e., values that aren't returned, passed to hooks, or used in JSX).
// Example: Pruning non-escaping scopes
function Component(props) {
// This object doesn't escape, so the playground will show
// that its memoization scope has been pruned.
const internalValue = { a: props.a };
// This value escapes via the return statement,
// so the playground will show an active reactive scope.
const output = [props.b];
return output;
}
In the playground, you can verify this by looking for the PruneNonEscapingScopes pass to see which variables were excluded from memoization to reduce code size and runtime overhead.
Validation and Errors
The playground surfaces compiler-level validation errors in real-time. This is particularly useful for identifying patterns that violate React's rules or the compiler's specific constraints.
Capitalized Function Calls
The compiler enforces that capitalized functions should be rendered as JSX components rather than called as regular functions. If you trigger a ValidateNoCapitalizedCalls error, the playground will highlight the call site:
function Component() {
// ERROR: Capitalized functions are reserved for components.
// The playground will suggest rendering this as <SomeComponent />.
const x = SomeComponent();
return <div>{x}</div>;
}
Configuring the Compiler
You can test different compiler configurations directly in the playground using file-level pragmas. These pragmas mimic the options available in the Babel plugin configuration:
// @compilationMode(infer): Tells the compiler to infer whether a component should be compiled.// @validateNoCapitalizedCalls(true): Enables strict checks for capitalized function calls.// @enablePreserveExistingMemoizationGuarantees: Forces the compiler to respect manualuseMemooruseCallbackboundaries for comparison.
Example Configuration
// @compilationMode(infer)
// @validatePreserveExistingMemoizationGuarantees
import { useMemo } from 'react';
function MyComponent({ data }) {
return useMemo(() => compute(data), [data]);
}
By toggling these settings in the playground, you can see how different configuration flags impact the final generated code and the granularity of the reactive scopes.