CI/CD & GitHub Actions
The React repository employs a robust CI/CD pipeline powered by GitHub Actions to manage the complexity of its monorepo architecture. The automation strategy is bifurcated into two primary domains: Runtime Build & Test and Compiler Validation.
Workflow Architecture
React's CI environment is designed to validate changes across different execution contexts (DOM, Native, Server) and build stages (Development, Profiling, Production).
Runtime Build and Test
The primary runtime workflow (runtime_build_and_test.yml) handles the validation of core React packages.
- Unit Testing: Executes the Jest suite across all core packages (
react,react-dom,scheduler). - Integration Testing: Runs cross-package integration tests to ensure compatibility between the reconciler and various renderers.
- Size Tracking: Monitors bundle size deltas for production artifacts to prevent performance regressions.
Compiler Build and Test
The React Compiler (located in compiler/) follows a specialized CI path (compiler_typescript.yml). This pipeline focuses on the static analysis and transformation logic of the Babel plugin.
- Type Checking: Strict TypeScript validation across the
babel-plugin-react-compilerand its dependencies. - HIR Analysis: Validates the High-level Intermediate Representation (HIR) generation and optimization passes.
Static Analysis and Validation
The CI pipeline integrates custom validation passes that enforce React's architectural constraints during the compilation phase.
Rule Validation
The compiler includes specific validation modules like ValidateNoCapitalizedCalls.ts. This pass ensures that developers do not invoke capitalized functions directly, as these are reserved for JSX components.
// Internal logic for capitalized call validation
export function validateNoCapitalizedCalls(fn: HIRFunction): Result<void, CompilerError> {
// Logic to detect: const x = SomeFunc();
// Error: Capitalized functions are reserved for components and must be invoked with JSX.
}
Escape Analysis and Scope Pruning
A critical part of the CI's performance validation is the PruneNonEscapingScopes pass. This internal logic identifies identifiers that do not "escape" the local function scope (i.e., they are not returned or passed to hooks).
- Escaping Criteria: A value escapes if it is directly returned, transitively aliased by a return value, or passed as an argument to a hook (e.g.,
useEffect). - Pruning Logic: The CI validates that the compiler prunes reactive scopes that are not necessary for downstream computation, reducing memoization overhead.
Automated Regression Testing (Fixtures)
The compiler utilizes a fixture-based testing system to prevent regressions. These tests are located in __tests__/fixtures/compiler/.
Fixture Structure
Each test case is defined by a source file and an exported FIXTURE_ENTRYPOINT configuration. This allows the CI to execute the compiled code against specific inputs and verify output consistency.
// Example: compiler/packages/.../fixtures/compiler/example-test.js
function Component(props) {
const x = [...props.items].map(item => item);
return x;
}
export const FIXTURE_ENTRYPOINT = {
fn: Component,
params: [{items: [{id: 1}]}],
sequentialRenders: [
{items: [{id: 1}]},
{items: [{id: 2}]},
],
};
Sequential Render Validation
For components and hooks, the CI executes Sequential Renders. This ensures that the memoization logic generated by the compiler correctly invalidates and updates state across multiple render cycles without breaking React's contract.
Release Channels
React's CI/CD pipeline automates the distribution of artifacts to multiple npm channels:
| Channel | Description | Trigger |
| :--- | :--- | :--- |
| Latest | Stable releases for general production use. | Manual/Scheduled Tag |
| Canary | Features that are heading towards a stable release. | Merges to main |
| Experimental | Features in early development (e.g., new Compiler flags). | Feature branches |
| Nightly | Automated builds reflecting the latest state of main. | Cron schedule |
To use a specific build from the CI pipeline, you can point your package.json to the specific hash or tag generated by the GitHub Action workflow.