Skip to content

feat(bridge): federated SSR demo with React host and Vue/React remotes#1

Draft
tonoizer wants to merge 37 commits into
mainfrom
cursor/bridge-app-ssr-e63b
Draft

feat(bridge): federated SSR demo with React host and Vue/React remotes#1
tonoizer wants to merge 37 commits into
mainfrom
cursor/bridge-app-ssr-e63b

Conversation

@tonoizer

@tonoizer tonoizer commented Jun 29, 2026

Copy link
Copy Markdown
Owner

Summary

Adds framework-agnostic federated bridge SSR with a deliberately small surface area.

Core contract (unchanged)

Server: loadRemote → provider.renderToString() → { html, state }
Client: createRemoteAppComponent({ ssrHtml, ssrState }) → hydrate

What changed

  • bridge-shared: SSR protocol (serializeBridgeSSRState, markers, state scripts) + shared renderRemoteBridgeToString
  • bridge-react / bridge-vue3: provider renderToString, thin host wrappers, RemoteAppWrapper hydration
  • bridge-ssr-demo: Express + Rsbuild reference host (React + Vue remotes, Nuxt-style client nav)

Simplifications (this pass)

  • One host helperrenderRemoteBridgeToString in bridge-shared; React adds asset collection only
  • Removed dead/duplicate APIsbridgeAppSSRPlugin, remoteModuleCache, public RemoteSSRMarkup, deprecated wrapBridgeSSRHtml
  • Two client paths only — lazy CSR (no SSR) + minimal SSR-hydrate loader (no Suspense mismatch on direct visits)
  • Host concerns stay in demo — URL normalization moved out of shared package; unused /_bridge/ssr-context endpoint removed
  • No hover/preload wiring in demo (Suspense fallback is enough for CSR nav)

Framework / bundler agnostic design

Layer Host responsibility
Server Call renderRemoteAppToString in any SSR pipeline
Remote createBridgeComponent with renderToString via MF ssr environment
Client Pass ssrHtml + ssrState to createRemoteAppComponent

Validation

  • pnpm exec turbo run test --filter=@module-federation/bridge-shared --filter=@module-federation/bridge-react --filter=@module-federation/bridge-vue3
  • pnpm run e2e:bridge:ssr — 11 Playwright + 5 Cypress (16/16)

Changeset

Minor bump for @module-federation/bridge-react, @module-federation/bridge-vue3, @module-federation/bridge-shared.

Open in Web Open in Cursor 

@github-actions

github-actions Bot commented Jun 29, 2026

Copy link
Copy Markdown

Bundle Size Report

38 package(s) changed, 4 unchanged.

Package dist + ESM entry

Package Total dist (raw) Delta ESM gzip Delta
@module-federation/bridge-react 331.8 kB -53926 B (-13.7%) 1.3 kB -3 B (-0.2%)
@module-federation/bridge-react-webpack-plugin 13.0 kB -99182 B (-88.2%) 1.6 kB -10631 B (-87.0%)
@module-federation/bridge-shared 26.1 kB +25.1 kB (+2463.2%) 3.1 kB +3.0 kB (+2221.9%)
@module-federation/bridge-vue3 203.0 kB +27.0 kB (+15.3%) 151 B -26203 B (-99.4%)
@module-federation/cli 25.5 kB -893 B (-3.3%) 810 B +24 B (+3.1%)
@module-federation/devtools 1.00 MB +360.2 kB (+54.1%) 4.0 kB +5 B (+0.1%)
@module-federation/dts-plugin 332.9 kB +19.5 kB (+6.2%) 4.7 kB no change
@module-federation/enhanced 815.9 kB +5.9 kB (+0.7%) 672 B no change
@module-federation/esbuild 255.1 kB -13453 B (-4.9%) 67 B -49 B (-42.2%)
@module-federation/inject-external-runtime-core-plugin 5.2 kB no change 519 B -1 B (-0.2%)
@module-federation/managers 70.7 kB +735 B (+1.0%) 244 B -90 B (-26.9%)
@module-federation/manifest 132.0 kB -4207 B (-3.0%) 106 B -76 B (-41.8%)
@module-federation/metro 275.9 kB -1338 B (-0.5%) 112 B -35 B (-23.8%)
@module-federation/metro-plugin-rnef 8.6 kB +168 B (+1.9%) 108 B -3 B (-2.7%)
@module-federation/metro-plugin-rock 8.6 kB +168 B (+1.9%) 108 B -3 B (-2.7%)
@module-federation/modern-js 200.6 kB +6.2 kB (+3.2%) 1.2 kB no change
@module-federation/modern-js-v3 193.9 kB +6.1 kB (+3.3%) 876 B +1 B (+0.1%)
@module-federation/native-federation-tests 93.1 kB +6 B (+0.0%) 745 B no change
@module-federation/native-federation-typescript 91.6 kB +16 B (+0.0%) 629 B no change
@module-federation/nextjs-mf 163.3 kB +35.5 kB (+27.8%) 160 B no change
@module-federation/node 198.0 kB +4.6 kB (+2.4%) 217 B no change
@module-federation/observability-plugin 282.0 kB +225 B (+0.1%) 150 B no change
@module-federation/playground 28.92 MB +75.7 kB (+0.3%) 47.0 kB -4968 B (-9.4%)
@module-federation/retry-plugin 43.1 kB +432 B (+1.0%) 2.8 kB no change
@module-federation/rsbuild-plugin 108.0 kB -12122 B (-9.9%) 62 B -29 B (-31.9%)
@module-federation/rspack 56.5 kB -4134 B (-6.7%) 161 B -50 B (-23.7%)
@module-federation/rspress-plugin 19.6 kB -327 B (-1.6%) 4.5 kB -3 B (-0.1%)
@module-federation/runtime-core 294.1 kB +6.4 kB (+2.2%) 570 B +93 B (+19.5%)
@module-federation/sdk 128.9 kB -100 B (-0.1%) 785 B no change
@module-federation/storybook-addon 80.1 kB +933 B (+1.2%) 100 B no change
@module-federation/third-party-dts-extractor 20.0 kB -40215 B (-66.3%) 2.0 kB +64 B (+3.3%)
@module-federation/treeshake-frontend 626.5 kB -2834 B (-0.4%) 0 B no change
@module-federation/treeshake-server 774.2 kB -38676 B (-4.7%) 124 B -8047 B (-98.5%)
@module-federation/utilities 107.6 kB -3115 B (-2.7%) 227 B -101 B (-30.8%)
@module-federation/webpack-bundler-runtime 67.7 kB -31270 B (-31.1%) 531 B +126 B (+31.1%)
create-module-federation 11.9 kB -368 B (-2.9%) 3.5 kB -24 B (-0.7%)

Bundle targets

Package Web bundle (gzip) Delta Node bundle (gzip) Delta
@module-federation/bridge-react 14.4 kB -3773 B (-20.4%) 15.4 kB -3781 B (-19.4%)
@module-federation/bridge-react-webpack-plugin 995 B -6876 B (-87.4%) 995 B -6876 B (-87.4%)
@module-federation/bridge-shared 2.7 kB +2.6 kB (+2132.3%) 2.7 kB +2.6 kB (+2132.3%)
@module-federation/bridge-vue3 21.4 kB +2.5 kB (+13.4%) 21.7 kB +2.5 kB (+13.0%)
@module-federation/cli 2.3 kB +29 B (+1.2%) 2.4 kB +2 B (+0.1%)
@module-federation/core 1.0 kB -3 B (-0.3%) 1.0 kB -35 B (-3.2%)
@module-federation/devtools 30.3 kB +115 B (+0.4%) 30.3 kB +93 B (+0.3%)
@module-federation/dts-plugin 15.3 kB +1.2 kB (+8.6%) 15.3 kB +1.2 kB (+8.6%)
@module-federation/enhanced 2.7 kB +7 B (+0.3%) 2.8 kB -46 B (-1.6%)
@module-federation/inject-external-runtime-core-plugin 391 B -1 B (-0.3%) 391 B -1 B (-0.3%)
@module-federation/managers 2.4 kB +52 B (+2.1%) 2.4 kB +52 B (+2.1%)
@module-federation/manifest 5.5 kB -17 B (-0.3%) 5.5 kB -17 B (-0.3%)
@module-federation/metro 9.4 kB -81 B (-0.8%) 9.4 kB -81 B (-0.8%)
@module-federation/metro-plugin-rnc-cli 416 B -1 B (-0.2%) 435 B -27 B (-5.8%)
@module-federation/modern-js 5.1 kB +178 B (+3.5%) 5.1 kB +178 B (+3.5%)
@module-federation/modern-js-v3 5.0 kB +177 B (+3.6%) 5.0 kB +177 B (+3.6%)
@module-federation/nextjs-mf 5.1 kB +427 B (+8.8%) 5.1 kB +427 B (+8.8%)
@module-federation/node 9.2 kB +5 B (+0.1%) 9.2 kB -30 B (-0.3%)
@module-federation/playground 42.8 kB -5113 B (-10.4%) 42.8 kB -5113 B (-10.4%)
@module-federation/rsbuild-plugin 4.3 kB -206 B (-4.4%) 4.3 kB -206 B (-4.4%)
@module-federation/rspack 2.7 kB -9 B (-0.3%) 2.7 kB -10 B (-0.4%)
@module-federation/rspress-plugin 3.1 kB +2 B (+0.1%) 3.1 kB +2 B (+0.1%)
@module-federation/runtime-core 15.3 kB +304 B (+2.0%) 15.1 kB +309 B (+2.0%)
@module-federation/sdk 4.4 kB +3 B (+0.1%) 5.9 kB -35 B (-0.6%)
@module-federation/third-party-dts-extractor 1.3 kB +14 B (+1.1%) 1.3 kB +14 B (+1.1%)
@module-federation/treeshake-server 5.6 kB -63 B (-1.1%) 5.6 kB -63 B (-1.1%)
@module-federation/utilities 2.2 kB +7 B (+0.3%) 2.2 kB +7 B (+0.3%)
@module-federation/webpack-bundler-runtime 4.1 kB +101 B (+2.5%) 4.1 kB +101 B (+2.5%)

Tree-shakable entrypoints

Package Export Entry gzip Delta Web bundle (gzip) Delta Node bundle (gzip) Delta Gap (node-web) Delta
@module-federation/webpack-bundler-runtime ./bundler 151 B no change 4.1 kB +101 B (+2.5%) 4.1 kB +101 B (+2.5%) 0 B 0 B

Consumer scenarios

Scenario Web output (gzip) Delta Node output (gzip) Delta Gap (node-web) Delta
Enhanced remoteEntry 21.4 kB +37 B (+0.2%) 23.1 kB +3 B (+0.0%) +1.7 kB -34 B

Total dist (raw): 35.97 MB (+275.8 kB (+0.8%))
Total ESM gzip: 85.4 kB (-46959 B (-34.9%))
Total web bundle (gzip): 243.8 kB (-8245 B (-3.2%))
Total node bundle (gzip): 246.5 kB (-8504 B (-3.3%))
Tracked ./bundler entry gzip: 556 B (no change)
Tracked ./bundler web bundle (gzip): 4.8 kB (+101 B (+2.1%))
Tracked ./bundler node bundle (gzip): 4.8 kB (+101 B (+2.1%))

Bundle sizes are generated with rslib (Rspack). Package-root metrics preserve the historical report. Tracked subpath exports such as ./bundler are measured separately so ENV_TARGET-driven tree-shaking is visible. Bare imports are externalized to keep package-level sizes consistent, and assets are emitted as resources.

@cursor cursor Bot changed the title feat(bridge): add application-level SSR support for React and Vue feat(bridge): application-level SSR for bridge remotes Jun 29, 2026
@cursor
cursor Bot force-pushed the cursor/bridge-app-ssr-e63b branch from 93c4f36 to a9e18d0 Compare June 30, 2026 06:36
@cursor cursor Bot changed the title feat(bridge): application-level SSR for bridge remotes feat(bridge): federated SSR demo with React host and Vue/React remotes Jun 30, 2026
dmchoi77 and others added 25 commits July 6, 2026 11:44
…4787)

Co-authored-by: Zack Jackson <[email protected]>
Co-authored-by: ScriptedAlchemy <[email protected]>
Co-authored-by: Hanric <[email protected]>
@tonoizer
tonoizer force-pushed the cursor/bridge-app-ssr-e63b branch from d927242 to c203d59 Compare July 18, 2026 13:10
@cursor
cursor Bot force-pushed the cursor/bridge-app-ssr-e63b branch from 2915de3 to 2c3f1e5 Compare July 18, 2026 16:32
cursoragent and others added 2 commits July 18, 2026 16:36
Key the hydration registry by moduleName+instanceId, hydrate empty islands
from markers, destroy React roots when mount DOM identity changes, require a
registry for client references, and soft-cancel aborted Vue mounts so failed
renders cannot leak remotes.
Claim registry snapshots before provider.render and fail them on cancel so
SPA revisits cannot hydrate stale request-time state. KeepAlive reactivation
falls back to CSR, and demo hosts stop re-seeding SSR refs after navigation.

Co-authored-by: Cursor <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.