Thanks to visit codestin.com
Credit goes to github.com

Skip to content

fix(ssr): load federated remotes in general Vite SSR setups#723

Merged
gioboa merged 5 commits into
module-federation:mainfrom
tonoizer:fix/vite-ssr-remote-loading
May 22, 2026
Merged

fix(ssr): load federated remotes in general Vite SSR setups#723
gioboa merged 5 commits into
module-federation:mainfrom
tonoizer:fix/vite-ssr-remote-loading

Conversation

@tonoizer

Copy link
Copy Markdown
Contributor

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:

  • host and remotes live in the same monorepo (nuxt demo), and
  • the server imports remote files by relative path, bypassing federation.

That is not the integration model most Vite + Module Federation users expect. We need SSR to work when:

  • each app runs on its own origin/port
  • the host loads remotes through federation only
  • nested remotes SSR correctly (e.g. host → remote_a → remote_b)

Result

Users can:

  1. Use the same federation imports on client and server
  2. Run host and remotes as separate apps without monorepo file imports on the server

@tonoizer

Copy link
Copy Markdown
Contributor Author

I could create a demo in your repo @gioboa with a pkg-pr-new version if you allow it.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread src/plugins/pluginMFManifest.ts Outdated

@gioboa gioboa left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks sure. Feel free to create an example there, much appreciated 👏

@pkg-pr-new

pkg-pr-new Bot commented May 19, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@module-federation/vite@723

commit: dc52578

@gioboa gioboa left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your help @tonoizer 🙏
This PR is changing many things, I am waiting for your example to verify if there is any room for improvements or changes.

@tonoizer

Copy link
Copy Markdown
Contributor Author

Still tinkering a bit, as you said many changes maybe I can trim it down and make it work for nuxt, tanstack etc.

@gioboa

gioboa commented May 20, 2026

Copy link
Copy Markdown
Collaborator

Nuxt and tanstack are already working with full SSR. You can find the apps in the examples repo.

@tonoizer

Copy link
Copy Markdown
Contributor Author

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 null on the server: https://github.com/gioboa/module-federation-vite-examples/blob/main/tanstack/remote/src/components/Widget.tsx#L32

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 gioboa left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what are your thoughts?

Yes, I agree that we should aim for a frictionless configuration and improve this area.

@gioboa

gioboa commented May 20, 2026

Copy link
Copy Markdown
Collaborator

In the TanStack example, the remote widget currently returns null on the server: https://github.com/gioboa/module-federation-vite-examples/blob/main/tanstack/remote/src/components/Widget.tsx#L32

I removed this check because it's not needed.

Going on with the other fix.

@gioboa gioboa left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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),

@Nsttt Nsttt left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

tonoizer and others added 3 commits May 21, 2026 12:30
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]>
@tonoizer tonoizer force-pushed the fix/vite-ssr-remote-loading branch from c4d7c9d to cf066b7 Compare May 21, 2026 11:47
@tonoizer

tonoizer commented May 21, 2026

Copy link
Copy Markdown
Contributor Author

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!

@tonoizer tonoizer requested review from Nsttt and gioboa May 21, 2026 14:09

@gioboa gioboa left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tests With Different Frameworks

Screenshot 2026-05-22 at 11 30 51

@gioboa gioboa left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You rock 👏
Thank you @tonoizer

@gioboa gioboa merged commit e722d70 into module-federation:main May 22, 2026
19 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants