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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions