Skip to content

Vite 8 (Rolldown): dynamicLoadingCss called with __v__css__ string instead of array, causing TypeError: e.forEach is not a function #740

@mehmeterslann

Description

@mehmeterslann

Versions

  • @originjs/vite-plugin-federation: 1.4.1
  • vite: 8.0.1 (Rolldown bundler)
  • @vitejs/plugin-react: 4.3.4
  • tailwindcss: 4.2.2 with @tailwindcss/postcss
  • react: 19.2.4

What is Expected?

Remote apps should load correctly. The dynamicLoadingCss() function should receive an array of real CSS file paths (e.g., ["./style-abc123.css"]).

What is Happening?

With Vite 8 (which uses the Rolldown bundler), the generated remoteEntry.js calls dynamicLoadingCss() with a virtual module string instead of an array:

// Generated by vite-plugin-federation@1.4.1 + Vite 8:
"./App": () => (
  a(`__v__css__/path/to/App.tsx`, false, `./App`),
  o("./__federation_expose_App-XYZ.js").then(...)
)

But the dynamicLoadingCss function (a) does:

var a = (e, t, n) => {
  // ...
  e.forEach(e => { /* create <link> tag */ })
}

e is the __v__css__ string. String.prototype.forEach does not exist → TypeError: e.forEach is not a function is thrown.

This causes the entire remote module to fail to load, and the host app shows "Failed to load [remote]" via its ErrorBoundary.

Root Cause

Vite 8 uses Rolldown as its bundler. Rolldown represents CSS associated with a module using virtual module IDs prefixed with __v__css__. The federation plugin picks up these virtual IDs and passes them as-is to dynamicLoadingCss(), which expects an array of real relative file paths.

Reproduction

  1. Set up Module Federation with @originjs/vite-plugin-federation@1.4.1 + vite@8.0.1
  2. Use Tailwind CSS v4 with @tailwindcss/postcss in remote apps
  3. Build a remote app — inspect dist/assets/remoteEntry.js
  4. Look for: a(\v__css/path/to/Component.tsx`, false, `./App`)`
  5. Load the remote from the host — observe TypeError: e.forEach is not a function

Workaround

Post-build, patch remoteEntry.js to replace the virtual module ID with the actual CSS bundle file reference:

// Before:
a(`__v__css__/path/to/App.tsx`, false, `./App`)
// After:
a(["./style-abc123.css"], false, `./App`)

Or as a Vite plugin in vite.config.ts:

function fixFederationCss(): Plugin {
  return {
    name: "fix-federation-css",
    apply: "build",
    closeBundle() {
      const assetsDir = path.resolve(__dirname, "dist/assets");
      const remoteEntry = path.join(assetsDir, "remoteEntry.js");
      if (!fs.existsSync(remoteEntry)) return;
      const cssFile = fs.readdirSync(assetsDir).find(f => /^style-.*\.css$/.test(f));
      let code = fs.readFileSync(remoteEntry, "utf8");
      const replacement = cssFile ? `a(["./${cssFile}"],` : "a([],";
      code = code.replace(/a\(`__v__css__[^`]+`,/g, replacement);
      fs.writeFileSync(remoteEntry, code);
    },
  };
}

Additional Notes

The fix should be applied in the plugin itself: before generating dynamicLoadingCss() calls, filter out virtual module IDs (starting with __v__css__) and resolve them to the actual CSS asset file in the build output.

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