import react from "@vitejs/plugin-react"; import reactCompiler from "babel-plugin-react-compiler"; // ONE React transform, shared by vite.config.ts and vitest.config.ts (E27 S1). // // It is a shared factory rather than two `react()` calls because the two configs must not drift: // if the compiler ran only in the production build, every vitest run would be exercising code the // user never receives, and a compiler-induced behaviour change would ship green. That is precisely // the defect `0.93.2` was released to fix — a gate and a build image that had quietly stopped being // the same thing — so the rule here is that the gate compiles the code the same way the build does. // // The React Compiler auto-memoises: it infers what `useCallback`/`useMemo` were being hand-written // for and applies the equivalent itself. It is enabled repo-wide with no opt-out list because it // bails out on its own for anything it cannot prove safe — SILENTLY: `panicThreshold` is "none" and // there is no logger here, so a skipped component still works and simply re-renders everything under // it. This comment used to say "its rules are also linted"; it was false while `react-hooks/refs` was // off, and 95 functions sat uncompiled behind it (E32). What actually holds the line now is // src/components/compilerCoverage.contract.test.ts, which runs THIS compiler over the shipped source // and fails on any skip not on its list; the react-hooks lint rules are the early warning. None of // them is off (three run at the preset's warn, which `--max-warnings 0` fails — docs/gates.md), but // three of the compiler's diagnostics cannot report under the installed plugin (eslint.config.js // says which), so the ratchet is the line, not the lint. `target` follows the installed React major and // must move with it. // // The plugin is IMPORTED rather than named by the usual `"babel-plugin-react-compiler"` string. Two // reasons, both about the gate: a string is invisible to knip, which then reports the dependency as // unused, and — worse — a typo in that string is a silent no-op that ships an uncompiled bundle, // while a bad import is a resolve error on the tsc lane. // // The price of the import: plugin-react finds the compiler only by that string, so it doesn't know the // compiler is there. Its one compiler-specific switch is Babel's `retainLines`, which it turns on for // dev (and so for vitest) unless the compiler is present. With the compiler's re-printed JSX that eats // the space at the end of a text line ("for example " rendered "for example/api/feed"). The // production build never had it on. `generatorOpts` wins over the top-level option, so it is switched // off here, for every mode. Pinned by src/jsxWhitespace.dom.test.tsx. export const reactWithCompiler = () => react({ babel: { plugins: [[reactCompiler, { target: "19" }]], generatorOpts: { retainLines: false }, }, });