From a9a6fa58f8701d952349f6d743afc2a1685ab580 Mon Sep 17 00:00:00 2001 From: Badcuban <108198679+badcuban@users.noreply.github.com> Date: Sat, 31 Oct 2026 01:17:35 -0400 Subject: [PATCH] build(web): run the React Compiler on worker threads Babel, running the React Compiler, is most of the web app's build time. @rolldown/plugin-babel 0.3 can run it on worker threads, but only with options it can send to them, and plugin-react's compiler preset holds its Babel half as a function. We call that function once and pass the plain result; the preset's filters and hooks stay in the main process. Measured on this Mac, four workers (the plugin's default cap): - vp build: 21s to 9.5s, with byte-identical output (diff -rq dist) - dev server, first cold page load: 6.4s to 3.5s - web browser suite: 95s to 78s, 927 tests passing The workers add about 350 MB to a running dev server. Hot updates still apply. --- apps/web/vite.config.ts | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/apps/web/vite.config.ts b/apps/web/vite.config.ts index d5fc9a1d0..321cd44b6 100644 --- a/apps/web/vite.config.ts +++ b/apps/web/vite.config.ts @@ -1,7 +1,7 @@ import { fileURLToPath } from "node:url"; import tailwindcss from "@tailwindcss/vite"; import react, { reactCompilerPreset } from "@vitejs/plugin-react"; -import babel from "@rolldown/plugin-babel"; +import babel, { type RolldownBabelPreset } from "@rolldown/plugin-babel"; import { tanstackRouter } from "@tanstack/router-plugin/vite"; import { resolveGitReleaseVersion } from "@threadlines/shared/gitVersion"; import { defineProject, type TestProjectInlineConfiguration } from "vite-plus/test/config"; @@ -128,6 +128,19 @@ const unitTestProject = { }, } satisfies TestProjectInlineConfiguration; +/** + * plugin-react's React Compiler preset with its Babel half (a function that + * names the compiler plugin) called here, so the preset is plain data that + * plugin-babel can send to its worker threads. Its filters and hooks stay in + * this process. + */ +function reactCompilerWorkerPreset(): RolldownBabelPreset { + const compiler = reactCompilerPreset(); + return typeof compiler.preset === "function" + ? { ...compiler, preset: compiler.preset() } + : compiler; +} + export function createWebPlugins(options?: { readonly routerAutoCodeSplitting?: boolean; }): PluginOption[] { @@ -145,7 +158,10 @@ export function createWebPlugins(options?: { // whereas the previous version of the plugin parsed all files with a .ts extension. // This caused our packages/ directory to fail to parse, as they are not relative to the CWD. parserOpts: { plugins: ["typescript", "jsx"] }, - presets: [reactCompilerPreset()], + presets: [reactCompilerWorkerPreset()], + // Babel (the React Compiler) is most of a build's time; run it on up + // to four worker threads. + parallel: true, exclude: [ // The plugin's default, which an explicit exclude replaces. /[/\\]node_modules[/\\]|^\0rolldown\/runtime\.js$/,