From f428a9e67805eef7a51b81c3ccc21aff8b6bd956 Mon Sep 17 00:00:00 2001 From: Siddharth Kshetrapal Date: Wed, 19 Aug 2026 15:37:15 +0200 Subject: [PATCH 1/2] fix: bundle React Compiler runtime into dist Compiled modules import a bare 'react-compiler-runtime' specifier; externalizing it makes a callable 'c' depend on the consumer env, which crashes with '(0, l.c) is not a function' when it can't be resolved. Bundle the runtime into dist so it is self-contained. --- .changeset/bundle-react-compiler-runtime.md | 5 +++++ packages/react/rolldown.config.ts | 10 +++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) create mode 100644 .changeset/bundle-react-compiler-runtime.md diff --git a/.changeset/bundle-react-compiler-runtime.md b/.changeset/bundle-react-compiler-runtime.md new file mode 100644 index 00000000000..19c51ba683a --- /dev/null +++ b/.changeset/bundle-react-compiler-runtime.md @@ -0,0 +1,5 @@ +--- +'@primer/react': patch +--- + +Bundle the React Compiler runtime (`react-compiler-runtime`) into the published output instead of importing it as an external dependency, so compiled components no longer crash in environments where the consumer cannot resolve a callable runtime. diff --git a/packages/react/rolldown.config.ts b/packages/react/rolldown.config.ts index e3c65d4e847..5e26fd3cfc8 100644 --- a/packages/react/rolldown.config.ts +++ b/packages/react/rolldown.config.ts @@ -44,9 +44,13 @@ const dependencies = [ ...Object.keys(packageMetadata.peerDependencies ?? {}), ...Object.keys(packageMetadata.dependencies ?? {}), ...Object.keys(packageMetadata.devDependencies ?? {}), -].map(name => { - return new RegExp(`^${name}(/.*)?`) -}) +] + // Bundle the React Compiler runtime into dist instead of externalizing it, so + // consumers never depend on their own environment resolving a callable `c`. + .filter(name => name !== 'react-compiler-runtime') + .map(name => { + return new RegExp(`^${name}(/.*)?`) + }) const external = [ // Exclude package dependencies From de8b3d34bf29d79c4f33a1e303e5d66d0cc945ef Mon Sep 17 00:00:00 2001 From: Siddharth Kshetrapal Date: Wed, 19 Aug 2026 16:15:49 +0200 Subject: [PATCH 2/2] refactor: bundle only the compiler memo helper via a local shim Alias 'react-compiler-runtime' to a local ESM shim exporting only 'c', instead of bundling the whole CommonJS package (dead code + require interop). Also anchor the external regex to a name boundary so 'react' no longer matches 'react-compiler-runtime' (which made externalization impossible to opt out of). --- .changeset/bundle-react-compiler-runtime.md | 2 +- packages/react/rolldown.config.ts | 27 ++++++++++++++++--- packages/react/script/react-compiler.mjs | 1 + .../react/src/utils/react-compiler-runtime.ts | 27 +++++++++++++++++++ 4 files changed, 53 insertions(+), 4 deletions(-) create mode 100644 packages/react/src/utils/react-compiler-runtime.ts diff --git a/.changeset/bundle-react-compiler-runtime.md b/.changeset/bundle-react-compiler-runtime.md index 19c51ba683a..8eced70cf99 100644 --- a/.changeset/bundle-react-compiler-runtime.md +++ b/.changeset/bundle-react-compiler-runtime.md @@ -2,4 +2,4 @@ '@primer/react': patch --- -Bundle the React Compiler runtime (`react-compiler-runtime`) into the published output instead of importing it as an external dependency, so compiled components no longer crash in environments where the consumer cannot resolve a callable runtime. +Bundle the React Compiler memo helper (`c`) into `@primer/react` via a local ESM shim instead of importing it from the external `react-compiler-runtime` package. This prevents a runtime crash (`TypeError: (0, l.c) is not a function`) when a consumer's bundle cannot resolve a callable `c`. diff --git a/packages/react/rolldown.config.ts b/packages/react/rolldown.config.ts index 5e26fd3cfc8..bd44b7df39c 100644 --- a/packages/react/rolldown.config.ts +++ b/packages/react/rolldown.config.ts @@ -40,16 +40,36 @@ function getEntrypointsFromInput(input: ReadonlySet) { ) } +// The React Compiler emits `import {c} from 'react-compiler-runtime'`. Alias it +// to a local ESM shim that is bundled into the output, so the memo helper is +// self-contained instead of an external CommonJS dependency that can fail to +// resolve a callable `c` in a consumer's bundle. +const reactCompilerRuntimeShim = path.resolve('src/utils/react-compiler-runtime.ts') + +function reactCompilerRuntimeAlias() { + return { + name: 'react-compiler-runtime-alias', + resolveId(source: string) { + if (source === 'react-compiler-runtime') { + return {id: reactCompilerRuntimeShim, external: false} + } + return null + }, + } +} + const dependencies = [ ...Object.keys(packageMetadata.peerDependencies ?? {}), ...Object.keys(packageMetadata.dependencies ?? {}), ...Object.keys(packageMetadata.devDependencies ?? {}), ] - // Bundle the React Compiler runtime into dist instead of externalizing it, so - // consumers never depend on their own environment resolving a callable `c`. + // `react-compiler-runtime` is aliased to a local shim and bundled, so it must + // not be external. .filter(name => name !== 'react-compiler-runtime') + // Anchor to a package-name boundary so a name isn't treated as a prefix of + // another (e.g. `react` must not match `react-compiler-runtime`). .map(name => { - return new RegExp(`^${name}(/.*)?`) + return new RegExp(`^${name}($|/)`) }) const external = [ @@ -70,6 +90,7 @@ export default defineConfig([ { input, plugins: [ + reactCompilerRuntimeAlias(), babel({ include: /\.(?:js|jsx|ts|tsx)$/, exclude: /node_modules/, diff --git a/packages/react/script/react-compiler.mjs b/packages/react/script/react-compiler.mjs index 01de9a0fbbd..95455a8f350 100644 --- a/packages/react/script/react-compiler.mjs +++ b/packages/react/script/react-compiler.mjs @@ -30,6 +30,7 @@ const unsupportedPatterns = [ 'src/hooks/useResizeObserver.ts', 'src/hooks/useSafeTimeout.ts', 'src/TooltipV2/Tooltip.tsx', + 'src/utils/react-compiler-runtime.ts', ] const unsupported = new Set( diff --git a/packages/react/src/utils/react-compiler-runtime.ts b/packages/react/src/utils/react-compiler-runtime.ts new file mode 100644 index 00000000000..d1c286f222f --- /dev/null +++ b/packages/react/src/utils/react-compiler-runtime.ts @@ -0,0 +1,27 @@ +import React, {useMemo} from 'react' + +// Local replacement for the `c` helper from `react-compiler-runtime`. The build +// aliases the compiler's `import {c} from 'react-compiler-runtime'` to this file +// so only `c` is bundled (as clean ESM), instead of externalizing the whole +// CommonJS package. Mirrors the upstream behavior: prefer React's built-in +// compiler runtime (React 19+), otherwise fall back to a `useMemo`-backed cache. +const MEMO_CACHE_SENTINEL = Symbol.for('react.memo_cache_sentinel') + +type MemoCache = Array + +function useMemoCache(size: number): MemoCache { + return useMemo(() => { + const cache = new Array(size) as MemoCache & Record + for (let index = 0; index < size; index++) { + cache[index] = MEMO_CACHE_SENTINEL + } + cache[MEMO_CACHE_SENTINEL] = true + return cache + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []) +} + +const builtinRuntime = (React as typeof React & {__COMPILER_RUNTIME?: {c?: (size: number) => MemoCache}}) + .__COMPILER_RUNTIME + +export const c: (size: number) => MemoCache = typeof builtinRuntime?.c === 'function' ? builtinRuntime.c : useMemoCache