-
Notifications
You must be signed in to change notification settings - Fork 398
Description
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.
- We can do basic module federation of components using
enhanced/runtime
(this works) - 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
- start the host app
- start the ssr-profile app
- 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
- What is the proper mechanism to do pure SSR functionality that does not expose the requests to the frontend if not useLoaderData?
- If useLoaderData is the proper mechanism what are we missing?
- 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',
},