Skip to content

[Bug]: Module Federation Runtime with Pages + useDataLoader crashes #6855

@zackarychapple

Description

@zackarychapple

Version

System:
    OS: macOS 15.3.1
    CPU: (16) arm64 Apple M4 Max
    Memory: 2.57 GB / 64.00 GB
    Shell: 5.9 - /bin/zsh
  Browsers:
    Chrome: 133.0.6943.127
    Safari: 18.3
  npmPackages:
    @modern-js/app-tools: 2.65.1 => 2.65.1 
    @modern-js/runtime: 2.65.1 => 2.65.1 
    @modern-js/tsconfig: 2.65.1 => 2.65.1

Details

We have a goal of using Module Federation together with ModernJS. The repository I am creating is trying to leverage enhanced to attempt to demonstrate several capabilities.

  1. We can do basic module federation of components using enhanced/runtime (this works)
  2. We can do advanced module federation of routes that have server side rendered data (this does not)

Reproduce link

https://github.com/zackarychapple/modern-mf-example2

Reproduce Steps

  1. start the host app
  2. start the ssr-profile app
  3. start the header app

When we import this remote into the header we are able to see the Async boundary as well as the delay in loading. Our initial understanding was that because this is wrapped in Await, the data fetch to the Pokemon api would be performed on the server (especially since this is being run with ssr streaming mode enabled.

const SsrProfile = React.lazy(() =>
  loadRemote('ssrprofile/ssr-profile').then((m) => {
    return m;
  }),
);

After some further digging we made an attempt to expose another federated remote that has useLoaderData which does in fact do SSR and only renders the data when pulled up manually. However when we try to federate it into the header we get an error.

const PreRenderedPokemon = React.lazy(() =>
  loadRemote('ssrprofile/rendered').then((m) => {
    return m;
  }),
);

The error

Unexpected Application Error!
useLoaderData must be used within a data router. See https://reactrouter.com/routers/picking-a-router.

Questions

  1. What is the proper mechanism to do pure SSR functionality that does not expose the requests to the frontend if not useLoaderData?
  2. If useLoaderData is the proper mechanism what are we missing?
  3. It seems there are some documentation and example discrepancies around using the enhanced runtime and the modernjs configs.
    Should we be using this methodology in the components themselves
registerRemotes([
  {
    name: 'ssrprofile',
    entry: 'http://localhost:4002/remoteEntry.js',
  }
]);

const SsrProfile = React.lazy(() =>
  loadRemote('ssrprofile/ssr-profile').then((m) => {
    return m;
  }),
);

Or should we be using this in the module-federation.config.ts that is loaded via the moduleFederationPlugin in modern.config.ts

  remotes: {
    ssrprofile: 'ssrprofile@http://localhost:4002/remoteEntry.js',
  },

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions