Skip to content

react/compiler-runtime chunk imports React directly instead of through importShared — broken hooks in remote builds #742

@pedrotainha

Description

@pedrotainha

Description

When a remote app uses React Compiler (babel-plugin-react-compiler), Rollup bundles react/compiler-runtime as a separate chunk. This chunk imports React via a direct static import:

import{r as R}from"./index-XYZ.js";  // direct React import

The plugin's AST transform in remote-production.ts converts import ... from 'react'importShared('react'), but it only matches exact module names (line 326-327):

parsedOptions.prodShared.some(
  (sharedInfo) => sharedInfo[0] === moduleName  // exact match only
)

react/compiler-runtime is a sub-export of react — it doesn't match 'react' exactly, so it's never transformed. The result: the compiler-runtime chunk gets its own React instance (from the bundled ./index-XYZ.js), separate from the host's shared React.

At render time, the shared React has its hooks dispatcher initialized (__CLIENT_INTERNALS...H), but the compiler-runtime's isolated copy has H = null → crash:

TypeError: Cannot read properties of null (reading 'useMemoCache')

Impact

This only affects remote builds (apps with exposes). The host owns the React instance directly, so its compiler-runtime works fine.

Reproduction

  • Host shares react via federation
  • Remote uses babel-plugin-react-compiler
  • Build remote → compiler-runtime-*.js chunk has import{r}from"./index-*.js" (direct import, not importShared)
  • Load remote in host → useMemoCache crashes

Suggested fix

In the generateBundle hook of remote-production.ts, detect compiler-runtime chunks and rewrite them to obtain React through importShared("react") via the __federation_fn_import chunk:

// Before (direct import — isolated React)
import{r as R}from"./index-XYZ.js";
var r=R().__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE;
export function c(n){return r.H.useMemoCache(n)}

// After (shared React via importShared)
import{importShared as __s}from"./__federation_fn_import-XYZ.js";
var __react=await __s("react");
var __internals=__react.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE;
var __obj={c:function(n){return __internals.H.useMemoCache(n)}};
export{__obj as c};

The patch should only apply to remote builds (builderInfo.isRemote), since the host doesn't need it.

Environment

  • vite-plugin-federation: 1.4.1
  • React: 19.x
  • babel-plugin-react-compiler: latest
  • Vite: 7.x

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions