fix(ssr): load federated remotes in general Vite SSR setups#723
Conversation
|
I could create a demo in your repo @gioboa with a pkg-pr-new version if you allow it. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8483704a84
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
gioboa
left a comment
There was a problem hiding this comment.
Thanks sure. Feel free to create an example there, much appreciated 👏
commit: |
|
Still tinkering a bit, as you said many changes maybe I can trim it down and make it work for nuxt, tanstack etc. |
|
Nuxt and tanstack are already working with full SSR. You can find the apps in the examples repo. |
|
I’m aware that these examples work, but to me the DX here is not a small detail. In the TanStack example, the remote widget currently returns Maybe we should verify whether that guard is actually required, but if it is, it means the remote component is effectively client-only and every SSR-safe remote may need this kind of hydration workaround. That feels like a DX issue to me. On the Nuxt side, I also don’t love that the host has to differentiate between SSR and CSR imports: https://github.com/gioboa/module-federation-vite-examples/blob/main/nuxt/host/app/app.vue#L17 Especially because the SSR path imports the remote component via a direct file path rather than through the remote itself. That works in a monorepo example, but it seems brittle for real-world usage. For example, what happens when the remote is deployed separately or is only available via URL/CDN and not present in the same repository? Ideally, the host should be able to use the same import for both SSR and CSR, e.g. something like: const RemoteWidget = defineAsyncComponent(() => import("remote/Widget"));and the federation/runtime layer should resolve the correct server or client implementation internally. That’s one thing I really like in the Rspack versions: you can stick with the standard remote import for both SSR and CSR. I think it would be a much better DX if the site examples could work the same way, what are your thoughts? |
gioboa
left a comment
There was a problem hiding this comment.
what are your thoughts?
Yes, I agree that we should aim for a frictionless configuration and improve this area.
I removed this check because it's not needed. Going on with the other fix. |
gioboa
left a comment
There was a problem hiding this comment.
On the Nuxt side, I also don’t love that the host has to differentiate between SSR and CSR imports: https://github.com/gioboa/module-federation-vite-examples/blob/main/nuxt/host/app/app.vue#L17
Fixed this one as well. Now there is only one import.
eg.
loader: () => import("remote/Counter").then((m) => m.default || m),
Point dev mf-manifest ssrRemoteEntry at /__mf_ssr__/ for all apps (not only Nuxt). Prefer /__mf_server__/remoteEntry.ssr.js in ssrEntryLoader so preview uses the SSR build graph instead of the client federation graph (fixes host hang when loading nested remotes). Co-authored-by: Cursor <[email protected]>
Nuxt only materializes federation assets from the client environment. When Vite 8 environments include ssr, skipping client emit left preview without remoteEntry.ssr.js and the host loaded the browser entry in Node. Co-authored-by: Cursor <[email protected]>
Walk up from Vite config.root to detect Nuxt (including .nuxt cache dirs). Emit remoteEntry.ssr.js on the client federation pass and skip the Nitro ssr pass so the file is copied into .output/public for preview. Co-authored-by: Cursor <[email protected]>
c4d7c9d to
cf066b7
Compare
|
Alright sorry guys for the long delay. I had a few issues initially because I was used to use the mf-manifest.json not the remoteEntry.js and at least it currently is not behaving the same in Vite as in rspack (maybe next issue I will tackle after this pr is done) but now my initial use case demo works locally and I committed the new changes as addition to your nuxt changes you added already 🙏 hopefully this works now and I can create a PR for the demos after. (I also fixed a issue nuxt preview had) Basically the demo’s I wanted to use is building onto of custom ssr setups as described in the Vite Docs (create-vite-extra) The demo’s I want to create are basically using the 2 step builds as provided by the create-vite-extra demo’s and then via the new site environment api, with multiple remotes and nesting. Can you run CI again for a PR version so I can provide a proper demo PR in your repo, thanks! |

Summary
PR #722 improved Nuxt SSR, but SSR can still break in the common Vite federation setup where remotes are served separately and apps use normal federation imports (e.g.
import Feature from 'remote_a/Feature') instead of importing remote source from disk.This PR closes that gap for plain Vite SSR: discover SSR remote entries reliably, emit them from the correct build graph, and load them on the server in dev and preview/production.
Problem
Today, SSR often only works when:
That is not the integration model most Vite + Module Federation users expect. We need SSR to work when:
host → remote_a → remote_b)Result
Users can: