@fulgurjs/federation 5.9.3 → 6.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/CHANGELOG.md +66 -0
  2. package/README.en.md +57 -416
  3. package/README.md +56 -446
  4. package/dist/bridge-app-vue.d.cts +1 -1
  5. package/dist/bridge-app-vue.d.ts +1 -1
  6. package/dist/bridge-core.cjs +1 -1
  7. package/dist/bridge-core.js +2 -2
  8. package/dist/bridge-errors.cjs +1 -1
  9. package/dist/bridge-errors.js +1 -1
  10. package/dist/bridge-host-react.cjs +1 -1
  11. package/dist/bridge-host-react.js +3 -3
  12. package/dist/bridge-host-vue.cjs +1 -1
  13. package/dist/bridge-host-vue.js +3 -3
  14. package/dist/bridge-router-react.d.ts +22 -3
  15. package/dist/bridge-router-react.js +107 -9
  16. package/dist/bridge-router-vue.d.ts +24 -5
  17. package/dist/bridge-router-vue.js +4 -5
  18. package/dist/{chunk-YKIFZIBH.js → chunk-77JZ6U6V.js} +1 -1
  19. package/dist/{chunk-Q6V5O5Y6.js → chunk-ENT3BOTX.js} +1 -1
  20. package/dist/{chunk-WRJG2YG6.js → chunk-ZAYNS7YQ.js} +1 -1
  21. package/dist/cli.js +460 -109
  22. package/dist/index.cjs +25 -38
  23. package/dist/index.js +25 -38
  24. package/dist/react-adapter.d.cts +7 -0
  25. package/dist/react-adapter.d.ts +7 -0
  26. package/dist/react.d.ts +229 -101
  27. package/dist/react.js +4 -0
  28. package/dist/runtime-entry.d.ts +27 -174
  29. package/dist/runtime-entry.js +0 -1
  30. package/dist/runtime.js +19 -17
  31. package/dist/vue-adapter.cjs +13 -1
  32. package/dist/vue-adapter.d.cts +1 -0
  33. package/dist/vue-adapter.d.ts +1 -0
  34. package/dist/vue-adapter.js +14 -2
  35. package/dist/vue.d.ts +594 -0
  36. package/dist/vue.js +8 -0
  37. package/docs/en/migration.md +210 -0
  38. package/docs/en/reference/api.md +555 -0
  39. package/docs/en/reference/errors.md +86 -0
  40. package/docs/{P5-vite7-8 → maintainers/P5-vite7-8}/345/205/274/345/256/271/347/237/251/351/230/265.md +7 -9
  41. package/docs/{webpack-mf- → maintainers/webpack-mf-}/345/257/271/347/205/247/344/270/216/347/274/272/345/217/243.md +10 -10
  42. package/docs/maintainers//346/262/231/347/256/261/350/276/271/347/225/214/345/256/241/350/256/241.md +43 -0
  43. package/docs/zh/migration.md +210 -0
  44. package/docs/zh/reference/api.md +551 -0
  45. package/docs/zh/reference/errors.md +86 -0
  46. package/examples/templates/README.md +1 -1
  47. package/examples/templates/react-host-vue-remote/pnpm-lock.yaml +7 -7
  48. package/examples/templates/react-host-vue-remote/pnpm-workspace.yaml +1 -1
  49. package/examples/templates/react-host-vue-remote/react-host/README.md +2 -2
  50. package/examples/templates/react-host-vue-remote/react-host/package.json +1 -1
  51. package/examples/templates/react-host-vue-remote/react-host/src/main.tsx +2 -2
  52. package/examples/templates/react-host-vue-remote/scripts/dev.config.json +11 -2
  53. package/examples/templates/react-host-vue-remote/vue-remote/package.json +1 -1
  54. package/examples/templates/react-host-vue-remote/vue-remote/src/bridge.ts +1 -1
  55. package/examples/templates/react-react/host/package.json +1 -1
  56. package/examples/templates/react-react/pnpm-lock.yaml +7 -7
  57. package/examples/templates/react-react/pnpm-workspace.yaml +1 -1
  58. package/examples/templates/react-react/remote/package.json +1 -1
  59. package/examples/templates/react-react/scripts/dev.config.json +11 -2
  60. package/examples/templates/showcase/README.md +6 -6
  61. package/examples/templates/showcase/pnpm-lock.yaml +11 -11
  62. package/examples/templates/showcase/pnpm-workspace.yaml +1 -1
  63. package/examples/templates/showcase/react-host/package.json +1 -1
  64. package/examples/templates/showcase/react-host/src/pages/BridgeVuePage.tsx +1 -1
  65. package/examples/templates/showcase/react-host/src/routing.ts +1 -1
  66. package/examples/templates/showcase/react-remote/package.json +1 -1
  67. package/examples/templates/showcase/react-remote/src/bridge.tsx +1 -1
  68. package/examples/templates/showcase/scripts/dev.config.json +22 -4
  69. package/examples/templates/showcase/vue-host/package.json +1 -1
  70. package/examples/templates/showcase/vue-host/src/pages/BridgeReactPage.vue +1 -1
  71. package/examples/templates/showcase/vue-host/src/routing.ts +3 -13
  72. package/examples/templates/showcase/vue-remote/package.json +1 -1
  73. package/examples/templates/showcase/vue-remote/src/bridge.ts +2 -2
  74. package/examples/templates/vue-host-react-remote/pnpm-lock.yaml +7 -7
  75. package/examples/templates/vue-host-react-remote/pnpm-workspace.yaml +1 -1
  76. package/examples/templates/vue-host-react-remote/react-remote/package.json +1 -1
  77. package/examples/templates/vue-host-react-remote/scripts/dev.config.json +11 -2
  78. package/examples/templates/vue-host-react-remote/vue-host/README.md +2 -2
  79. package/examples/templates/vue-host-react-remote/vue-host/package.json +1 -1
  80. package/examples/templates/vue-host-react-remote/vue-host/src/App.vue +2 -2
  81. package/examples/templates/vue-vue/host/package.json +1 -1
  82. package/examples/templates/vue-vue/host/src/main.ts +28 -21
  83. package/examples/templates/vue-vue/host/src/pages/HomePage.vue +1 -1
  84. package/examples/templates/vue-vue/pnpm-lock.yaml +7 -7
  85. package/examples/templates/vue-vue/pnpm-workspace.yaml +1 -1
  86. package/examples/templates/vue-vue/remote/package.json +1 -1
  87. package/examples/templates/vue-vue/scripts/dev.config.json +11 -2
  88. package/package.json +24 -37
  89. package/dist/bridge-core-D37VanBl.d.ts +0 -99
  90. package/dist/bridge-host-react-CGymCzD2.d.ts +0 -35
  91. package/dist/bridge-host-vue-B3GHaQAC.d.ts +0 -32
  92. package/dist/bridge-react.d.ts +0 -14
  93. package/dist/bridge-react.js +0 -3
  94. package/dist/bridge-vue.d.ts +0 -8
  95. package/dist/bridge-vue.js +0 -3
  96. package/dist/bridge.d.ts +0 -18
  97. package/dist/bridge.js +0 -5
  98. package/dist/chunk-GLASM5EX.js +0 -1730
  99. package/dist/chunk-V6EASSCR.js +0 -249
  100. package/dist/chunk-X34EJB4H.js +0 -207
  101. package/docs/API.en.md +0 -339
  102. package/docs/API.md +0 -914
  103. package/docs//346/262/231/347/256/261/350/276/271/347/225/214/345/256/241/350/256/241.md +0 -45
  104. package/docs//350/277/201/347/247/273/346/214/207/345/215/227.md +0 -179
@@ -0,0 +1,86 @@
1
+ # Error code table
2
+
3
+ > 48 error codes, grouped by segment: CFG (config time) / DEV (dev time) / BLD (build time) / MFU (runtime) / CC (cross-app context). Each entry gives the three-part **symptom / cause / fix**. The fix in the error message is concrete down to the config key / file / command; `fulgurjs doctor` can catch deployment-side MFU-001-class problems before release.
4
+ >
5
+ > Maintenance note: adding or changing an error code requires a three-place sync — the source code tables (the MFU segment in `src/runtime/errors.ts` / the CC segment in `src/context.ts`) + the registry `CODE_REGISTRY` (`src/diagnostics.ts`) + this table; `scripts/check-manual-codes.mjs` inside `npm run build` verifies the three-way consistency (see [maintainers · testing (Chinese)](../../maintainers/testing.md)).
6
+
7
+ ### 6. Error Code Table
8
+
9
+ #### CFG config-time
10
+
11
+ | Code | Symptom | Cause | Fix |
12
+ |---|---|---|---|
13
+ | `CFG-001` | At the vite config stage: "missing required name" or "invalid name format" | `federation({})` lacks a name, or the name does not match `/^[a-zA-Z][\w.-]*$/` (empty string / starts with a digit / contains spaces or slashes) | Declare a unique, non-empty string within the same page in `federation({ name: 'my-app' })` |
14
+ | `CFG-002` | Config stage: "exposes must be an object" or `exposes["x"].import missing` | exposes was written as an array/string, or an entry lacks its source file path | Write it as an object like `{ './Module': './src/path' }`; each key's value is a path string or `{ import: './src/path' }` |
15
+ | `CFG-003` | Config stage: "remotes key contains illegal characters" / "no address" | A remotes key contains `@`, `/`, or whitespace; or a remote has no address at all | Use a pure module name as the key (e.g. `remote-a`, which is also the import prefix); fill at least one of `external`/`dev`/`prod` |
16
+ | `CFG-004` | Config stage: "shared must be an array or object" | shared was written as a string or another illegal form | Use `['vue']` or `{ vue: { singleton: true } }` |
17
+ | `CFG-005` | Config stage: a remotes key collides with a shared key | The same name exists in both `remotes` and `shared` — the load rewrite rules would overwrite each other | Rename one of them (usually the remotes key; e.g. if `vue` is not allowed, use another prefix name) |
18
+ | `CFG-006` | Warning at startup: "no exposes or remotes configured; currently only shared dependencies are registered" | Isolated-island config: neither provides nor consumes (often caused by accidentally deleting exposes) | Configure `exposes` to provide modules; configure `remotes` to consume remotes |
19
+ | `CFG-007` | Config stage: "the object form does not support the name@ prefix" | `remotes['x'].dev/prod` written as `'bpm@http://…'` — in object form the whole string is treated as a URL to concatenate, producing a broken address (at runtime it shows up as an unrelated MFU-001) | Write prefix-free URLs in the object's dev/prod slots (the remote name defaults to the key); for a rename use the string form `'name@url'` |
20
+ | `CFG-008` | Config stage: "cannot configure both eager and import:false" or "shared key declared twice" | `eager` needs the local copy bundled into the initial chunk and is mutually exclusive with `import: false` (pure consumer); or the same shareKey+shareScope was declared twice | Pick one: `{ eager: true }` or `{ import: false }`; merge the duplicate declarations or use a different shareKey |
21
+ | `CFG-009` | Config stage: illegal timeout/retries/breaker numbers | `timeout`/`breaker.threshold`/`breaker.resetMs` not finite positives; `retries` not an integer 0–10 | `timeout: 15000`, `retries: 2` (capped at 10 to prevent retry storms), `breaker: { threshold: 5, resetMs: 30000 }` |
22
+ | `CFG-010` | Config stage: illegal devCorsOrigins form | The value is neither `"*"` nor an array of http(s) origins | `'*'` (fully open) or an allowlist like `['http://localhost:5100', …]` |
23
+ | `CFG-011` | Config stage: "option xxx was removed in 5.0.0" with the migration | A webpack-compatibility/invalid option was passed: `remoteType`/`library`/`automaticAsyncBoundary`/`dataPrefetch`/`usedExports`/`ignoreUnusedSharedExports` (any value, including historically valid ones, errors) | Delete the field outright: remoteEntry is always ESM, the TLA async boundary is always on, and tree-shaking is native to the bundler; for preloading use the runtime `preloadRemote()` (a `/runtime` export) |
24
+ | `CFG-012` | Config stage: "setup must be a non-empty module path relative to the app root" or "the exposes key is reserved by the federation setup entry" | setup is empty/non-string; or exposes occupies the reserved internal key `./__fulgurjs_setup__` | Write setup as e.g. `'./src/fulgurjs/setup.ts'`; rename the reserved key to another public expose and configure the original file path in `federation({ setup })` |
25
+
26
+ #### DEV dev-time
27
+
28
+ | Code | Symptom | Cause | Fix |
29
+ |---|---|---|---|
30
+ | `DEV-001` | Dev startup/first load reports a remote manifest fetch failure | The remote dev server is unreachable (not started / wrong port / network) | Confirm the remote dev server is running and `remotes[*].dev` is correct; check with `npx fulgurjs doctor --base http://localhost:<port> --apps <subdir> --dev` |
31
+ | `DEV-002` | Dev says the remote manifest is empty or of unrecognized format | The other side is not a fulgurjs plugin artifact, or the plugin version is so old the manifest shape is unrecognized | Install/upgrade @fulgurjs/federation on the other side and restart its dev server; verify you are hitting the `@fulgurjs-manifest.json` endpoint |
32
+ | `DEV-004` | Dev pre-bundling warning: a known UMD-only dependency is not in optimizeDeps.include | A UMD/CJS dependency was moved out of pre-bundling, risking the pre-bundle inlining a local vue | Put that dependency back into `optimizeDeps.include` (the plugin externalizes shared keys automatically) |
33
+ | `DEV-005` | Dev says the remotes dev URL port has no listener | No process is listening on the port of `remotes[*].dev` (the remote is not started, or its port changed without syncing) | Start the remote dev server; sync the host remotes dev addresses per the [port change checklist](../guide/examples.md#the-fixed-checklist-for-changing-ports) |
34
+ | `DEV-006` | Dev startup warns of host/remote plugin version mismatch | Different @fulgurjs/federation versions across apps on the same page (runtime copy risk) | Unify plugin versions across apps (align dependencies within a workspace; use the same version across repositories) |
35
+ | `DEV-009` | Dev page reports facade/virtual module 404 | `.vite` cache drift (after a plugin upgrade, the old cache no longer matches the new facade signatures) | `rm -rf node_modules/.vite` + restart the dev server (switch browser profile if needed) |
36
+ | `DEV-010` | Transient 504/"ce" or page reloads during the first 30–60s of a dev cold start | The Vite dependency pre-bundling window (new dependency discovery triggers re-optimization + full reload) — transient, not a failure | Open the page for real to warm up before asserting/testing; the steady state is unaffected |
37
+ | `DEV-011` | Dev startup reminder: non-loopback host + wildcard dev CORS | `devCorsOrigins` omitted/`'*'` and the host is exposed to the LAN — federation endpoints are open to any origin | Set `devCorsOrigins: '*'` explicitly (declaring awareness) or switch to an origin allowlist array |
38
+ | `DEV-012` | Dev startup reminder: non-loopback host + dev manifest carrying fsRoot | The dev manifest contains a local absolute path (`fsRoot`), which leaks the local path on non-loopback access | Set `devFsRoot: false` (host dts degrades to any stubs with a hint); `fsRoot` never enters the prod manifest |
39
+
40
+ #### BLD build-time
41
+
42
+ | Code | Symptom | Cause | Fix |
43
+ |---|---|---|---|
44
+ | `BLD-001` | Build reports an expose source file parse failure | The file at an `exposes` value does not exist / has a syntax error / the path points outside the project | Check the expose source paths (relative to the project root); fix the file or the path |
45
+ | `BLD-002` | Build reports a build target below es2022 | `build.target` is below es2022 — top-level await (TLA) needs it | `build.target: 'es2022'` or newer |
46
+ | `BLD-003` | Build warns that an expose target component has required props | An exposed component declared required props without defaults — when the host passes props through, rendering may lack them | Give required props defaults, or guarantee they are always passed at the usage site |
47
+ | `BLD-006` | Build reports that the negotiation facade chunk isolation cannot be injected automatically under an array-shaped output | `build.rollupOptions.output` is an array, so the plugin cannot add the facade chunk isolation branch automatically | Manually complete the isolation rules the plugin suggests in every output branch |
48
+
49
+ #### MFU runtime
50
+
51
+ | Code | Symptom | Cause | Fix |
52
+ |---|---|---|---|
53
+ | `MFU-001` | Runtime reports remote container/module load failure (network/timeout/retries exhausted/breaker open) | Remote unreachable, wrong entry address, retries exhausted after timeout, or the breaker opened after consecutive failures | Verify the remote address and availability; configure a `fallback` entry or tune `timeout`/`retries`; check the deployment side with `fulgurjs doctor` before release |
54
+ | `MFU-002` | Runtime reports the remoteEntry's self-reported name differs from the configured name | The container's self-reported name mismatches the `remotes` key / configured expectation (rename not aligned) | Align the remotes key with the self-reported name, or declare the rename explicitly with the string `'selfName@url'` form |
55
+ | `MFU-003` | Runtime throws strictVersion version mismatch | `strictVersion: true` (or the default rule hits) and the negotiated version fails `requiredVersion` | Align dependency versions across apps; or relax strictVersion/requiredVersion (after confirming compatibility) |
56
+ | `MFU-004` | Runtime reports a shared module missing with no local fallback | The requested shared key has no provider at all and this app provides no local copy (`import: false`); or an unprepared synchronous consumer hit an async resolveShare hook (`details.syncUnsupported: true`) | Confirm the provider's shared declarations and this side's load order; in custom entries `await loadShare(name, opts)` before dynamically importing the new consumer |
57
+ | `MFU-005` | Runtime reports the same container initialized twice with different share scopes | The same container was initialized with two different shareScopes (negotiation state ambiguity) | Unify that remote's shareScope (keep the remotes config consistent with runtime registration) |
58
+ | `MFU-006` | Runtime reports the requested module is not exposed by that remote | The spec's expose key does not match the remote's exposes list | Verify `remoteName/exposes key` (do not repeat the remote name prefix in the spec; `fulgurjs check-pages` can batch-verify) |
59
+ | `MFU-007` | Console warning of a preload failure (business not blocked) | A chunk/CSS prefetched by `preloadRemote` is unreachable | Check the `fulgurjs:error` event history and the remote deployment; preload failure does not affect the later real load |
60
+ | `MFU-008` | Runtime reports an unknown remote | The remote name in the spec/call is not in `remotes`/the runtime registry | Check the remote name spelling; for dynamic remotes call `registerRemote`/`registerRemotes` first |
61
+ | `MFU-009` | Runtime reports the loaded module has no exports | The expose target file has no exports (an empty module / side effects only) | Add exports to the expose target file; confirm the expected file is what got loaded |
62
+ | `MFU-010` | Runtime warns the selected shared singleton version fails some consumer's requirement (lists candidate versions, the provider, impact, and fixes; the same combination warns once) | The version singleton converged on is outside some consumer's requiredVersion; or a bridge host/child app missing singleton causes double-instance symptoms (Invalid hook call) | Align dependency versions; confirm the warning is acceptable or adjust requiredVersion; three singleton keys for cross-framework hosts |
63
+ | `MFU-011` | Runtime reports an illegal setup lifecycle entry export shape (reports actual type / expected signature / fix) | The setup module's default export or named `onSession` is not a function (other exports are not entries) | Default-export a `setup(context)` function from the setup file; optionally a named `onSession(context)` function |
64
+ | `MFU-012` | That `loadRemote` rejects, reporting setup/onSession threw (cause carries the original exception) | The initialization code itself threw | Fix the error inside setup/onSession and retry directly — only the failed stage's cache is cleared (after a setup failure the retry starts at setup; an onSession failure only reruns the session segment); already-successful stages are not repeated |
65
+ | `MFU-013` | Runtime reports the remote declares onSession but the host AppContext lacks sessionKey | The host did not provide a non-sensitive login generation ID (never use a token as one) | In the host login flow call `provideAppContext({ sessionKey })` — generate a new value on every successful login/re-login; token refreshes keep it |
66
+ | `MFU-014` | Runtime reports a recursive loadRemote of the same remote inside setup/onSession's synchronous segment | Loading a module of the same remote inside the initialization's synchronous segment — the call waits on itself, deadlocking | Do not load same-remote modules inside initialization; put cross-remote loads in the async segment |
67
+ | `MFU-015` | Runtime reports an illegal bridge contract (the `./bridge` default export lacks mount/unmount or they are not functions) | The module exposed as `./bridge` was not built with `defineBridgeApp` | Build the child app entry's default export with `defineBridgeApp(...)` (see [sub app bridge](../guide/app-bridge.md)) |
68
+ | `MFU-016` | Runtime reports bridge preparation or lifecycle failure (`details.phase` distinguishes getContext/mount/unmount; the root cause carries the child app's original error) | getContext returned a Promise/non-object, mount threw before the first commit, or unmount cleanup threw | Troubleshoot the child app code by phase: getContext must return a synchronous snapshot object; on mount failure clean up the app/root before throwing; fix unmount's cleanup logic — a container whose unmount threw is persistently locked out; recover with a full page refresh |
69
+ | `MFU-017` | Runtime reports bridge session parameters inconsistent with AppContext | The controlled `sessionKey` contradicts the global session (a getContext snapshot mismatch), an illegal value (empty string/number), or a page-level single-session conflict (generations mismatch across instances) | Unify the session across the page's controlled bridge instances; sessionKey takes only non-empty string/null/omitted; on generation switch follow "first null to unmount, clearAppContext, then write the new generation" |
70
+ | `MFU-030` | Bridge route sync configuration/prefix conflict error | Illegal basePath (empty/root/with query·hash·wildcard) or overlapping prefixes registered on one page | basePath is a static absolute path from the host routing perspective (e.g. `/approval`); prefixes of sync instances on one page must not overlap |
71
+ | `MFU-031` | Bridge reports a missing route protocol / dead channel | The host enabled routing but the child app did not declare `{ routing: true }`; or the channel was reused/re-subscribed after destruction | Declare `{ routing: true }` in the child app contract's second parameter and wire from `ctx.routing`; never revive an old channel after a session switch/unmount |
72
+ | `MFU-032` | Bridge reports an illegal navigation | The sub app navigates outside its own prefix (`../`, across prefixes), an illegal `go` argument, or a request on a dead channel | The sub app only navigates locations inside its own basePath; `go` takes legal integers; issue no navigation after the channel is invalidated |
73
+ | `MFU-033` | Bridge reports route preparation/sync failure (with the target chain/cause; never silently falls back to memory) | Guard/loader/port execution errors rejected, or more than 5 consecutive internal replaces (a redirect loop) | Fix the child app guard/loader errors; hunt down the redirect loop (cyclic redirects in the sub app's route definitions) |
74
+
75
+ #### CC cross-app context
76
+
77
+ | Code | Symptom | Cause | Fix |
78
+ |---|---|---|---|
79
+ | `CC-001` | Remote initialization throws a three-part error (got / expected / example) | A required field requested by `requireAppContext(...)` is missing from the AppContext | The host bridge calls `provideAppContext({...})` with the missing field before loading the remote (see [API reference · AppContext](api.md#2-appcontext--passing-values-and-method-references-across-apps)) |
80
+ | `CC-002` | The remote page reports the runtime singleton unavailable | The remote page was opened standalone (not loaded through the host federation) — no page-level runtime or context | Load the remote page through the host federation; timing contract: bridge → remote setup → page module |
81
+
82
+ ## Where to start troubleshooting
83
+
84
+ - By symptom (ignore the codes): [troubleshooting index](../troubleshooting/README.md)
85
+ - For config-stage errors run `npx fulgurjs explain` first; for deployment-side problems run `npx fulgurjs doctor` first
86
+ - Runtime diagnostics: `window.__FULGURJS_INFO__` (per-remote status and setup stage), `window.__FULGURJS_SCOPE__` (shared negotiation results), the `fulgurjs:error` event
@@ -16,13 +16,11 @@
16
16
 
17
17
  | Vite 版本 | @vitejs/plugin-vue | dev e2e | prod e2e | 备注 |
18
18
  |-----------|--------------------|---------|----------|------|
19
- | 5.1.4 | 4.x | ✅(历史轮) | ✅(历史轮) | testbed bpm 前基线 |
20
- | 5.2.12 | 4.x | ✅(历史轮) | ✅(历史轮) | testbed lowcode 前基线 |
21
- | 6.4.3 | ^5.2.0 | ✅ 10/10 | ✅ 8/8 | fixtures 默认版本 |
22
- | **7.3.6** | ^6.x | ✅ 10/10 | ✅ 8/8 | 本轮实测,零改动通过 |
23
- | **8.3.0** | ^6.x | ✅ 10/10 | ✅ 8/8 | 本轮实测,零改动通过 |
24
-
25
- (testbed 三应用分别使用 Vite 6.4.3/5.1.4/5.2.12,见 `docs/demo-app 环境事实`——真实工程同样覆盖。)
19
+ | 5.1.4 | 4.x | 通过(历史轮) | 通过(历史轮) | 早期基线 |
20
+ | 5.2.12 | 4.x | 通过(历史轮) | 通过(历史轮) | 早期基线 |
21
+ | 6.4.3 | ^5.2.0 | 通过 10/10 | 通过 8/8 | fixtures 默认版本 |
22
+ | **7.3.6** | ^6.x | 通过 10/10 | 通过 8/8 | 本轮实测,零改动通过 |
23
+ | **8.3.0** | ^6.x | 通过 10/10 | 通过 8/8 | 本轮实测,零改动通过 |
26
24
 
27
25
  ## 插件侧依赖 Vite 的注意点(7/8 下均验证无碍)
28
26
 
@@ -34,5 +32,5 @@
34
32
 
35
33
  ## 遗留
36
34
 
37
- - ~~Vite 8 原生 Rolldown 的完整 fixtures dev/prod e2e 矩阵仍未执行~~(2026-10-03 已补齐:vite 8.3.2 dev 73/73 + prod 33/33 随 CI 常驻矩阵,见验收报告 §12.2;Jeecg 企业级应用生产全场景 5/5,根因修复见 CHANGELOG 5.6.0)。
38
- - fixtures 只覆盖 vue 生态;react fixture 若将来补齐需同步扩 7/8 矩阵。(本轮已补 React 18/19 × vite8 代表性验证:R18+RR6 dev 34/34 + prod 20/20;R19+RR7 随基线矩阵。)
35
+ - Vite 8 原生 Rolldown 的完整 fixtures dev/prod e2e 矩阵:2026-10-03 起随 CI 常驻矩阵覆盖(vite 8.3.2 dev 73/73 + prod 33/33);Jeecg 企业级应用生产全场景 5/5(根因修复见 CHANGELOG 5.6.0)。
36
+ - fixtures 只覆盖 vue 生态;react fixture 若将来补齐需同步扩 7/8 矩阵。(已补 React 18/19 × vite8 代表性验证:R18+RR6 dev 34/34 + prod 20/20;R19+RR7 随基线矩阵。)
@@ -1,6 +1,6 @@
1
1
  # webpack Module Federation:当前能力与使用边界对照
2
2
 
3
- > 核对版本:`@fulgurjs/federation@5.7.1`(2026-10-03)。本页描述当前能力;早期任务书、设计方案及分版本验收报告保留历史记录,不作为当前支持范围。
3
+ > 核对版本:`@fulgurjs/federation@5.7.1`(2026-10-03 完成);6.0.0 统一入口(/vue、/react、/runtime)后本文入口路径已同步更新,能力语义不变。本页描述当前能力;早期历史过程文档不作为当前支持范围。
4
4
  > 对照对象是 webpack 5 内置 `ModuleFederationPlugin`;Module Federation enhanced runtime、Bridge、DevTools 等独立生态工具不是 webpack 内置插件的同一功能面。本插件不承诺完整配置或产物互操作兼容。
5
5
 
6
6
  ## 一、已经实现
@@ -13,14 +13,14 @@
13
13
  | `shared.import: false` | 支持 | 纯消费,不提供本地 fallback;不能与 eager 同时使用 |
14
14
  | 双向联邦与嵌套容器 | 支持 | 各应用可同时提供和消费模块;这不等于自动代理任意层级的桥接路由 |
15
15
  | Vue 3 / React 18–19 | 支持浏览器客户端 | 各框架组件加载、页面适配器;纯 TS 模块可跨框架消费 |
16
- | Vue ↔ React 子应用桥接 | 支持 | `/bridge` 整站挂载/卸载、props/context、会话切换、错误占位 |
17
- | 子应用路由 ↔ 宿主 URL | 支持,显式启用 | `/bridge/router/vue`、`/bridge/router/react`;深链、刷新、push/replace、前进后退与导航取消;默认关闭 |
16
+ | Vue ↔ React 子应用桥接 | 支持 | `defineBridgeApp`(`/vue`、`/react` 导出)+ `createVueBridgeApp`/`createReactBridgeApp`:整站挂载/卸载、props/context、会话切换、错误占位 |
17
+ | 子应用路由 ↔ 宿主 URL | 支持,显式启用 | `createVueBridgeNavigation`/`createReactBridgeNavigation`(宿主)+ `connectVueBridgeRouter`/`createReactBridgeRouter`(子应用),均从 `/vue`、`/react` 导入;深链、刷新、push/replace、前进后退与导航取消;默认关闭 |
18
18
  | React 18/19 隔离共存 | 支持按作用域隔离 | 整组 React、renderer 和消费者使用相应 scope;跨树传普通 props/回调,不能混用 ReactElement/Context |
19
19
  | 运行时策略 | 支持 | `runtimePlugins`;HTML 入口/expose 执行前准备异步共享策略。无 HTML 的入口及启动后修改策略须先协商再导入新消费者 |
20
20
  | 加载恢复与诊断 | 支持 | 超时、重试、熔断、显式 fallback、错误码;静态依赖失败的恢复边界见 §三 |
21
21
  | 工程辅助 | 支持 | dts、manifest 预载、setup/onSession、CLI 检查与 Demo |
22
22
 
23
- 入门步骤见 [中文 README](../README.md)、[英文 README](../README.en.md);公开签名及默认值见 [中文 API 手册](API.md)、[English API reference](API.en.md)。版本隔离与恢复例子见 [examples/demos/react-versions](../examples/demos/react-versions/README.md)。
23
+ 入门步骤见 [中文 README](../../README.md)、[英文 README](../../README.en.md);公开签名及默认值见 [中文 API 手册](../API.md)、[English API reference](../API.en.md)。版本隔离与恢复例子见 [examples/demos/react-versions](../../examples/demos/react-versions/README.md)。
24
24
 
25
25
  ## 二、当前不提供的能力
26
26
 
@@ -29,20 +29,20 @@
29
29
  | SSR / Node 服务端联邦、RSC、Next.js 全栈 | 不支持 | webpack 联邦概念支持 web/Node 等环境;不意味着自动获得完整 SSR/RSC 集成。本插件当前仅支持浏览器客户端 |
30
30
  | webpack `script` / `var` 容器互操作 | 不支持 | 本插件产出 ESM remote;不要因为都有 init/get 就直接混用两种产物。remoteType/library 已删除,传入报迁移错误 |
31
31
  | Vue/React 组件级直接混渲染 | 不提供转换层 | webpack 核心负责模块加载,不转换框架组件;本插件的子应用桥接允许两个框架各自管理组件树 |
32
- | JS 沙箱 / 自动 CSS 隔离 | 不提供 | 普通同页面联邦不会自动隔离全局变量、全局 CSS、Portal/Teleport 的容器外 DOM;需要额外隔离方案 |
32
+ | JS 沙箱 / 自动 CSS 隔离 | 不提供 | 普通同页面联邦不会自动隔离全局变量、全局 CSS、Portal/Teleport 的容器外 DOM;需要额外隔离方案(见[沙箱边界审计](沙箱边界审计.md)) |
33
33
  | 独立浏览器 DevTools 扩展 | 无 | 本插件提供 `window.__FULGURJS_SCOPE__ / __FULGURJS_INFO__`。其他联邦生态工具的扩展不能计为 webpack 内置能力 |
34
34
  | React 页面 KeepAlive | 不承诺 | 已下载模块可复用;组件状态保活需要应用或专门库实现 |
35
35
  | 其他框架与路由库的内置适配 | 无 | URL 同步内置 Vue Router / React Router data router;其他库可实现导航端口。多层桥接路由自动代理、跨窗口同步不在当前支持面 |
36
36
 
37
37
  ## 三、使用限制与 webpack 的区别
38
38
 
39
- 以下区分实例正确性、网络开销和失败恢复,不将“已测场景”扩大成所有工程保证。
39
+ 以下区分实例正确性、网络开销和失败恢复,不将"已测场景"扩大成所有工程保证。
40
40
 
41
41
  | 场景 | 本插件当前表现 | webpack 5 内置 MF 的对应表现 | 处理方法 |
42
42
  |---|---|---|---|
43
43
  | 共享库额外网络副本 | Vite 8 同步消费门面可能把未采用的本地副本也拉入模块图;已测双版本场景 ≤2 份。这不是所有应用图的数量上限;同 singleton scope 的实例身份仍统一 | 不是 webpack 的必然限制。异步 shared 可按协商结果加载;eager/fallback、未共享路径或不同 scope 也可能增加下载量,不能宣称 webpack 永远只下载一份 | 区分网络文件数与运行时实例数,按实际构建图评估;不要将本插件这项代价归为所有 MF 实现共有 |
44
44
  | dev 冷启动依赖优化重载 | Vite 新发现依赖时可能重新预构建并 full reload(DEV-010);稳定态需等优化完成 | webpack dev 也有编译/HMR 等待,但没有同一套 Vite 依赖优化机制 | 排查冷/热态区别,按需配置预构建;这不是生产限制,也不是 webpack MF 的相同缺陷 |
45
- | expose 的静态 ESM 依赖下载失败 | 已缓存失败的依赖 URL 可能阻止同页恢复;只变换 expose 入口 URL 不会改写静态依赖 URL,提供用户主动刷新恢复 | 常见 script/JSONP chunk loader 失败后清掉该 chunk 的加载状态,后续请求可以重新加载;仍需调用方触发重试。404 旧产物、持续网络故障等不保证靠重试恢复;使用原生 ESM 路径时需单独评估 | 不笼统写“webpack 也只能刷新”。本插件控制的入口/动态加载边界可变换 URL;静态依赖失败仍保留刷新操作 |
45
+ | expose 的静态 ESM 依赖下载失败 | 已缓存失败的依赖 URL 可能阻止同页恢复;只变换 expose 入口 URL 不会改写静态依赖 URL,提供用户主动刷新恢复 | 常见 script/JSONP chunk loader 失败后清掉该 chunk 的加载状态,后续请求可以重新加载;仍需调用方触发重试。404 旧产物、持续网络故障等不保证靠重试恢复;使用原生 ESM 路径时需单独评估 | 不笼统写"webpack 也只能刷新"。本插件控制的入口/动态加载边界可变换 URL;静态依赖失败仍保留刷新操作 |
46
46
  | React 与 renderer 不兼容或实例不一致 | React 18 的 renderer 不能因 singleton 协商就自动兼容 React 19。对齐版本,或分 scope 隔离整组依赖及消费者 | 同样受 React 的版本与实例要求约束;singleton 不会转换框架 ABI,strictVersion 可拒绝冲突 | 共享树使用兼容 React/renderer;不同大版本使用独立树和作用域,传普通数据/回调 |
47
47
 
48
48
  异步协商的启动时序同样需要关注:webpack 推荐异步 bootstrap 边界。本插件对 HTML 入口自动处理相关边界;自定义入口仍应先 `await loadShare`,再动态导入消费者。已经求值的静态绑定不能追溯替换。
@@ -58,7 +58,7 @@
58
58
 
59
59
  ## 四、迁移入口
60
60
 
61
- - Vite 工程按 [README](../README.md) 配置 remotes/exposes/shared,不照搬已经删除的 webpack 配置字段。
61
+ - Vite 工程按 [README](../../README.md) 配置 remotes/exposes/shared,不照搬已经删除的 webpack 配置字段。
62
62
  - 从 iframe/其他微前端方案迁移:先选择模块/页面加载或子应用桥接;需要地址恢复时显式开启 URL 同步。
63
- - React 18/19 同页运行:先运行 [版本隔离 Demo](../examples/demos/react-versions/README.md),再按实际应用依赖图配置作用域。
64
- - 旧报告里的“React 未支持”“URL 同步待实现”“Vite 8 生产挂起未解”属于旧版本记录。当前补修证据见 [完整验收报告 §14](完整Demo展示与全面复测-验收报告-20261002.md#14-共享协商收尾与证据订正571)。
63
+ - React 18/19 同页运行:先运行 [版本隔离 Demo](../../examples/demos/react-versions/README.md),再按实际应用依赖图配置作用域。
64
+ - 5.x → 6.0.0 的入口迁移(`/bridge`、`/bridge/router/*` 删除,功能并入 `/vue`、`/react`)逐条对照见[迁移指南](../zh/migration.md)。
@@ -0,0 +1,43 @@
1
+ # 沙箱边界审计(CSS / 全局变量 / 公共依赖)
2
+
3
+ > 日期 2026-09-16 | 实测脚本 `e2e/sandbox-audit.mjs`、`e2e/sandbox-audit2.mjs` | 环境 dev(宿主 + 多远程联邦加载前后对比)
4
+
5
+ ## 结论
6
+
7
+ **联邦没有沙箱,也不需要沙箱**——这是与 qiankun 类沙箱方案的根本架构差异。qiankun 用 JS Proxy 假 window + 样式隔离做「隔离共存」;@fulgurjs/federation(与 webpack MF 一致)做「**同 realm 共存 + 依赖级隔离**」:所有联邦模块与宿主跑在同一个 window/同一个 CSSOM 里,靠**共享依赖单例协商**防止最大的互扰源(双框架运行时),而不是靠沙箱隔开。
8
+
9
+ ## 观测维度(宿主 + 远程联邦加载前后对比)
10
+
11
+ ### 1. 全局变量(window)
12
+
13
+ - 联邦加载前后 window 新增键很少,且全部可解释:
14
+ - 框架类库的编译期 feature flags(如 `__VUE_I18N_*`/`__INTLIFY_*`,属库自身行为);
15
+ - 远程引入的第三方库全局(设计器/编辑器类库常见);
16
+ - 个别远程依赖把 Node 风格 CJS 包装漏到 window(`exports`/`fs` 等)——**这是子应用依赖自身的脏行为,与联邦无关**,无沙箱方案下同样存在;
17
+ - 联邦运行时唯一注册面:`window.__FULGURJS_SCOPE__`(share scope 列表)与 `window.__FULGURJS_INFO__`(远程加载状态)——无全局散落;
18
+ - 未发现远程覆盖宿主关键全局。团队约定:业务全局键加前缀,避免撞名。
19
+
20
+ ### 2. CSS
21
+
22
+ - expose chunk 的 CSS 由运行时自动加载(manifest 注入 `stylesheet` 链接,fixtures 用例覆盖);
23
+ - 风格主战场:Vue SFC scoped 样式(data-v hash)天然隔离;组件库 CSS 类名前缀(.el-/.avue-/.vxe- 等)天然分区;
24
+ - **已知理论边界**:多版本组件库 CSS 同挂 `:root` 变量,后加载覆盖先加载——各版本变量默认值一致时无实际影响;若某版本改了变量默认值,以「最后加载为准」,这是同 realm CSSOM 的固有权衡(webpack MF 同样如此)。全局样式(非 scoped、无前缀)仍可能影响宿主,需按约定收敛。
25
+
26
+ ### 3. 公共方法/依赖实例
27
+
28
+ | 类别 | 机制 | 观测证据 |
29
+ |------|------|---------|
30
+ | **shared 键**(vue/react/react-dom/router/store) | loadShare 协商单例,"已加载优先" | 双框架实例(如双 Vue)会直接崩溃(Invalid hook call / 'ce' 类报错);singleton 协商到同一实例后报错消失,即为单例实证 |
31
+ | **非 shared 依赖**(lodash-es、axios、组件库…) | 各远程自带副本,模块作用域隔离 | 互不干扰;代价是体积冗余(联邦的固有权衡) |
32
+ | **远程全局注册**(全局组件/指令) | `setup` 生命周期**显式**注册进宿主 app 实例,失败显式报错(无静默忽略) | 注册面在宿主 app 实例上清晰可见 |
33
+
34
+ ## 三、心智模型
35
+
36
+ | 维度 | qiankun 类沙箱方案 | @fulgurjs/federation |
37
+ |------|---------|--------------------|
38
+ | JS 运行环境 | Proxy 假 window 沙箱 | **同一 window,无沙箱** |
39
+ | CSS | 可选严格隔离/重写 scoped | **同一 CSSOM,无隔离**(靠 scoped 样式+类名前缀+依赖版本对齐) |
40
+ | 公共依赖 | 子应用各自打包(或 externals) | **shared 单例协商**(更强:运行时版本协商+双版本共存) |
41
+ | 适用代价 | 隔离带来适配成本(全局桥、样式穿透、性能损耗) | 无沙箱要求依赖收敛与命名纪律 |
42
+
43
+ **一句话**:联邦不做"防你犯错的隔离",做"让你们共享一切的编排"。全局变量要按团队约定加前缀;全局样式要 scoped 或带业务前缀;这三条纪律落实后,同 realm 联邦可长期无互扰运行。
@@ -0,0 +1,210 @@
1
+ # 6.0.0 迁移指南
2
+
3
+ > 6.0.0 完成**公共入口统一**:Vue 应用、React 应用、框架无关模块各有一个唯一入口,全部桥接与路由同步 API 并入 `/vue` 与 `/react`。本指南覆盖 5.x → 6.0.0 的全部破坏性变化,每条给出旧写法 → 新写法的对照与代码前后示例。历史版本(≤5.9.x)的更早破坏性变化(5.0.0 删除项)见文末附录。
4
+
5
+ ## 一、6.0.0 破坏性变化总表
6
+
7
+ | # | 变化 | 影响 | 迁移动作 |
8
+ |---|---|---|---|
9
+ | 1 | 删除入口 `/bridge`(聚合) | 从 `/bridge` 导入 `createVueBridgeApp`/`createReactBridgeApp` 的代码报 exports 解析错误 | 分别改从 `/vue`、`/react` 导入(见下文对照) |
10
+ | 2 | 删除入口 `/bridge/vue`、`/bridge/react` | Vue/React 桥接宿主工厂导入失败 | `createVueBridgeApp` → `@fulgurjs/federation/vue`;`createReactBridgeApp` → `@fulgurjs/federation/react` |
11
+ | 3 | 删除入口 `/bridge/router/vue`、`/bridge/router/react` | URL 同步 API 导入失败 | 四个路由同步 API 全部并入 `/vue`、`/react` |
12
+ | 4 | `/runtime` 不再导出 Vue 的 `remoteComponent`、`createHostPages`、`defineBridgeApp` | 曾从 `/runtime` 导入这三个 Vue API 的代码报导入为 undefined/类型错误 | 改从 `@fulgurjs/federation/vue` 导入;`/runtime` 保持框架无关(运行时全量 + context + pages + remoteSchema,零 Vue/React/router 依赖) |
13
+ | 5 | `fulgurjs init` 参数收敛:`--template` 更名 `--out` | 旧写法仍接受但按输出路径解释并打印更名提示(后续版本移除) | 改用 `fulgurjs init --out <路径>` |
14
+
15
+ 聚合 `/bridge` 在生产构建可摇树、但 **dev 原生 ESM 无摇树保证**(会同时执行两个宿主适配器)——统一入口后此问题消失:`/vue` 零 React、`/react` 零 Vue。
16
+
17
+ ## 二、导入对照表(旧 → 新)
18
+
19
+ | API | 旧导入(≤5.9) | 新导入(6.0.0) |
20
+ |---|---|---|
21
+ | `federation` / `FederationOptions` | `@fulgurjs/federation` | `@fulgurjs/federation`(不变) |
22
+ | `loadRemote`/`loadShare`/`preloadRemote`/`getContainer`/`registerRemote(s)`/`registerShare`/`initSharing`/`registerPlugins`/`getRuntime`/`shareScopeMap`/`unwrapDefault`/`version`/`clearSessionState`/`parseSpec`/`getLoadedShare`/`pinLoadedShare` | `@fulgurjs/federation/runtime`(或 `/vue`、`/react` 同名) | 不变;React 应用也可统一从 `/react` 导入 |
23
+ | `provideAppContext`/`getAppContext`/`requireAppContext`/`clearAppContext` | `/runtime`(或 `/vue`、`/react`) | 不变;框架无关 |
24
+ | `definePages`/`validatePages`/`remoteSchema` | `/runtime`(或 `/vue`、`/react`) | 不变 |
25
+ | `remoteComponent`(Vue 形态) | `@fulgurjs/federation/runtime` | **`@fulgurjs/federation/vue`** |
26
+ | `createHostPages`(Vue 形态) | `@fulgurjs/federation/runtime` | **`@fulgurjs/federation/vue`** |
27
+ | `remoteComponent`/`useLoadRemote`/`RemoteErrorBoundary`/`createReactHostPages`(React) | `@fulgurjs/federation/react` | 不变 |
28
+ | `defineBridgeApp`(Vue 子应用) | 旧入口 `/runtime` 或聚合 `/bridge` | **`@fulgurjs/federation/vue`** |
29
+ | `defineBridgeApp`(React 子应用) | 旧入口 `/react` 或聚合 `/bridge` | 不变(`/react`) |
30
+ | `createVueBridgeApp` | 旧入口 `bridge/vue`(或聚合 `/bridge`) | **`@fulgurjs/federation/vue`** |
31
+ | `createReactBridgeApp` | 旧入口 `bridge/react`(或聚合 `/bridge`) | **`@fulgurjs/federation/react`** |
32
+ | `createVueBridgeNavigation`/`connectVueBridgeRouter` | 旧入口 `bridge/router/vue` | **`@fulgurjs/federation/vue`** |
33
+ | `createReactBridgeNavigation`/`createReactBridgeRouter` | 旧入口 `bridge/router/react` | **`@fulgurjs/federation/react`** |
34
+ | `RuntimePlugin`/`RemoteConfig`/`SharedHint` 等类型 | `/runtime`、包根 | 不变 |
35
+
36
+ 记忆口诀:**「应用跑什么框架,就从哪个框架入口导入」**——Vue 的一切从 `/vue`,React 的一切从 `/react`,两者都要用的纯 TS 模块从 `/runtime`,Vite 配置从包根。
37
+
38
+ ## 三、代码前后示例
39
+
40
+ ### 3.1 Vue 子应用桥接契约
41
+
42
+ ```ts
43
+ // ── 旧(5.x)──
44
+ import { defineBridgeApp } from '@fulgurjs/federation/runtime'
45
+
46
+ export default defineBridgeApp((props) => {
47
+ const app = createApp(App, props)
48
+ return app
49
+ })
50
+ ```
51
+
52
+ ```ts
53
+ // ── 新(6.0.0)──
54
+ import { defineBridgeApp } from '@fulgurjs/federation/vue'
55
+
56
+ export default defineBridgeApp((props) => {
57
+ const app = createApp(App, props)
58
+ return app
59
+ })
60
+ ```
61
+
62
+ ### 3.2 Vue 宿主挂载 React 子应用
63
+
64
+ ```ts
65
+ // ── 旧(5.x):导入自旧入口 bridge/vue(@fulgurjs/federation 包根下,6.0.0 已删除)──
66
+ import { createVueBridgeApp } from '…/bridge/vue'
67
+ const RemoteReactApp = createVueBridgeApp('react-remote/bridge', { retries: 1 })
68
+ ```
69
+
70
+ ```ts
71
+ // ── 新(6.0.0)──
72
+ import { createVueBridgeApp } from '@fulgurjs/federation/vue'
73
+ const RemoteReactApp = createVueBridgeApp('react-remote/bridge', { retries: 1 })
74
+ ```
75
+
76
+ ### 3.3 URL 同步(Vue 宿主 + Vue 子应用两端)
77
+
78
+ ```ts
79
+ // ── 旧(5.x)──(旧入口 bridge/router/vue,6.0.0 已删除)
80
+ // 宿主
81
+ import { createVueBridgeNavigation, type BridgeHostRouting } from '…/bridge/router/vue'
82
+ const navigation = createVueBridgeNavigation(router)
83
+ const routing: BridgeHostRouting = { basePath: '/approval', navigation }
84
+ // 子应用
85
+ import { connectVueBridgeRouter } from '…/bridge/router/vue'
86
+ await connectVueBridgeRouter(ctx.routing!, router, { signal: ctx.signal }).ready
87
+ ```
88
+
89
+ ```ts
90
+ // ── 新(6.0.0)──
91
+ // 宿主(与 createVueBridgeApp 同一入口)
92
+ import { createVueBridgeApp, createVueBridgeNavigation, type BridgeHostRouting } from '@fulgurjs/federation/vue'
93
+ const navigation = createVueBridgeNavigation(router)
94
+ const routing: BridgeHostRouting = { basePath: '/approval', navigation }
95
+ // 子应用(与 defineBridgeApp 同一入口)
96
+ import { defineBridgeApp, connectVueBridgeRouter } from '@fulgurjs/federation/vue'
97
+ await connectVueBridgeRouter(ctx.routing!, router, { signal: ctx.signal }).ready
98
+ ```
99
+
100
+ ### 3.4 React 宿主 URL 同步
101
+
102
+ ```tsx
103
+ // ── 旧(5.x)──(旧入口 bridge/react 与 bridge/router/react,6.0.0 已删除)
104
+ import { createReactBridgeApp } from '…/bridge/react'
105
+ import { createReactBridgeNavigation, createReactBridgeRouter } from '…/bridge/router/react'
106
+ ```
107
+
108
+ ```tsx
109
+ // ── 新(6.0.0)──
110
+ import {
111
+ createReactBridgeApp,
112
+ createReactBridgeNavigation,
113
+ createReactBridgeRouter,
114
+ defineBridgeApp,
115
+ } from '@fulgurjs/federation/react'
116
+ ```
117
+
118
+ ### 3.5 Vue 宿主逐页接入(`/runtime` 的 Vue API 迁出)
119
+
120
+ ```ts
121
+ // ── 旧(5.x)──
122
+ import { createHostPages, remoteComponent } from '@fulgurjs/federation/runtime'
123
+ ```
124
+
125
+ ```ts
126
+ // ── 新(6.0.0)──
127
+ import { createHostPages, remoteComponent } from '@fulgurjs/federation/vue'
128
+ ```
129
+
130
+ ### 3.6 纯 TS 模块(无迁移)
131
+
132
+ ```ts
133
+ // 旧与新完全一致:框架无关代码始终从 /runtime 导入
134
+ import { loadRemote, loadShare } from '@fulgurjs/federation/runtime'
135
+ ```
136
+
137
+ ## 四、迁移步骤(机械替换即可完成)
138
+
139
+ 1. **全局搜索旧子路径**:在源码里搜 `bridge/vue`、`bridge/react`、`bridge/router/vue`、`bridge/router/react`、`/bridge'` 等旧入口引用——6.0.0 的包已删除这些 exports,构建会直接报错指出每一处;
140
+ 2. **按第二节对照表逐条改 import**:`/bridge/vue`、`/bridge/react`、`/bridge/router/vue`、`/bridge/router/react` 的内容分别并入 `/vue`、`/react`;同一文件多种桥接 API 会合并成一个 import 语句;
141
+ 3. **检查 `/runtime` 导入面**:从 `/runtime` 导入 `remoteComponent`/`createHostPages`/`defineBridgeApp` 的(Vue 专属 API),改从 `/vue` 导入;`/runtime` 其余导出不变;
142
+ 4. **TS 诊断收尾**:对改动文件跑 `vue-tsc --noEmit`/`tsc --noEmit`,确认无 `Failed to resolve import`/ts(2307);IDE 报 ts(2307) 时先 `Restart TS Server` 清 TS 服务缓存;
143
+ 5. **dev 验证请求图**:桥接宿主的 dev 首屏不再加载对方框架适配器(`/vue` 宿主零 React 执行,反之亦然);
144
+ 6. **`fulgurjs init --template` 调用方**:改用 `--out`(旧名仍可用但会打印更名提示)。
145
+
146
+ ## 五、从其他微前端方案接入(概念映射)
147
+
148
+ 从 qiankun 类方案迁入时的 API 级概念对应(通用技术结论,与具体业务无关):
149
+
150
+ | 旧方案概念 | @fulgurjs/federation 对应 |
151
+ |---|---|
152
+ | 主应用 registerMicroApps | 宿主 `federation({ remotes })` |
153
+ | 子应用 entry(HTML) | remote entry(dev: `@fulgurjs-entry.js` 中间件 / prod: `fulgurjs-remoteEntry.js`) |
154
+ | 子应用生命周期 mount/unmount | 页面级 exposes(组件即入口,无生命周期样板);启动期初始化 = 远程 `federation({ setup })`(setup/onSession);整应用嵌入 = 桥接契约的 `mount`/`unmount`(`defineBridgeApp`) |
155
+ | window 隔离/沙箱 | 无沙箱:同 realm 直渲染(结论与边界见[沙箱边界审计](../maintainers/沙箱边界审计.md)) |
156
+ | props 传递 | 组件 props(组件级);`appProps`(桥接级,挂载快照语义);AppContext(跨应用上下文) |
157
+ | 公共依赖 externals | `shared`(singleton 协商,"已加载优先") |
158
+ | qiankun 运行时 + single-spa | `@fulgurjs/federation/runtime`(运行时内核 20KB 级,无 single-spa) |
159
+
160
+ ## 六、页面卸载清理清单
161
+
162
+ 乾坤的 `unmount` 会强制子应用清理 window 级资源;联邦**组件级**卸载不会自动清——以下资源必须在页面组件 `onUnmounted`(React 用 effect cleanup)里自行摘除,否则切走再切回会重复注册/重复触发:
163
+
164
+ | 资源 | 清理方式 |
165
+ |---|---|
166
+ | `getAppContext().events.<前缀>.xxx = fn` 反向注册 | 卸载时删除该属性(比对函数引用后 delete) |
167
+ | `window.addEventListener(...)` | 记住函数引用,卸载时 `removeEventListener` |
168
+ | `setInterval` / `setTimeout` | 卸载时 `clearInterval` / `clearTimeout` |
169
+ | 自挂的其他全局键 | 同理显式删除 |
170
+
171
+ ```ts
172
+ import { onUnmounted } from 'vue'
173
+ import { getAppContext } from '@fulgurjs/federation/vue'
174
+
175
+ const onHostEvent = (e: unknown) => { /* ... */ }
176
+ getAppContext().events!.bpm = { onHostEvent }
177
+ onUnmounted(() => {
178
+ const events = getAppContext().events
179
+ if (events?.bpm?.onHostEvent === onHostEvent) delete events.bpm.onHostEvent
180
+ })
181
+ ```
182
+
183
+ > 轻量提醒而非插件机制:绝大多数页面只有数据请求(随组件销毁自然结束),无需任何清理;有全局副作用的页面按清单逐项过一遍即可。桥接挂载的完整子应用由契约 `unmount` 负责容器级清理;unmount 抛错会导致该容器被持久封锁(只能整页刷新),子应用清理逻辑务必健壮。
184
+
185
+ ## 七、首次使用避坑清单(通用工程问题)
186
+
187
+ | # | 坑 | 症状 | 解法 |
188
+ |---|-----|------|------|
189
+ | 1 | 插件升级后未清 `.vite` | 页面渲染回旧逻辑 / 门面签名漂移 404(DEV-009) | `rm -rf node_modules/.vite` + 重启 dev + 换浏览器 profile |
190
+ | 2 | pnpm 装 tarball 软链断链 | `Cannot find module '@fulgurjs/federation'` | 重新安装并验证目录可达 |
191
+ | 3 | UMD/CJS 依赖被移出预构建 | dev 裸 CJS 白屏、`Cannot destructure property 'node'`(DEV-004) | 放回 `optimizeDeps.include`(插件自动外部化 shared 键) |
192
+ | 4 | 给 shared 依赖加 ESM 别名 | 构建期 `xxx.default.extend is not a function` | **build 必删**(prod rollup 双重 interop);dev 侧若该依赖已移出预构建,其 CJS 子路径需 dev 专用别名兜住(`command==='serve'` 才注入) |
193
+ | 5 | 登录异步链未完成就断言 | e2e 偶发被弹回登录页 | 等「登录表单消失」而非固定秒数;慢链留足超时 |
194
+ | 6 | 多版本组件库 CSS | 后加载覆盖 `:root` 变量 | 主流版本变量一致则无感;升级时留意 |
195
+ | 7 | 后端缺端点 | 404/401 资源报错 | 代理/NGINX 层加诚实空响应垫片(不伪造业务数据) |
196
+ | 8 | 远程页面(exposes 目标文件)静态导入运行时 | 担心双实例 | 直接静态导入即可——插件自动改写为惰性单例代理,远程与宿主写法完全一致 |
197
+
198
+ ## 附录:5.0.0 删除的旧 API(跨版本升级者查阅)
199
+
200
+ 5.0.0 是有意的破坏性清理。旧 API 传入时一律得到中文的「当前值 → 原因 → 迁移写法」错误,不会被静默接受:
201
+
202
+ | 已删除(5.0.0) | 替代写法 |
203
+ |---|---|
204
+ | `@fulgurjs/federation/config` 子路径(`defineRepoConfig` / `loadRepoConfig` / `federationOptionsForApp` / `RepoConfig` 等聚合类型) | 每个应用根目录一份 `fulgurjs.config.ts`,默认导出直接 `satisfies FederationOptions`;`host.pages`/`remotePrefixes`/`deriveSpec` 改具名导出 `hostPages` |
205
+ | CLI `--app <应用名>`(聚合配置选择器) | 在各应用根目录直接运行 `fulgurjs explain` / `fulgurjs check-pages`;传 `--app` 会报中文错误 |
206
+ | check-pages 旧聚合形态的本地 dist 回退 | `--manifest <远程>=<路径\|URL>` 或 `--site <URL>`(显式来源失败如实报「无法验证」,不假装通过) |
207
+ | `federation()` 选项:`remoteType`、`library`、`automaticAsyncBoundary`、`dataPrefetch`、`usedExports`、`ignoreUnusedSharedExports` | 直接删除该字段:remoteEntry 恒为 ESM、TLA 异步边界恒开、tree-shaking 由打包器原生完成;需要预载时运行时调用 `preloadRemote()`(`/runtime` 导出)。传入任何值(含历史合法值)报 `CFG-011` |
208
+ | 旧「expose 启动器 + 宿主手动调用」初始化范式 | `federation({ setup })`:默认导出 `setup(context)` 应用级一次 + 具名导出 `onSession(context)` 会话级去重 |
209
+
210
+ 版本历史的完整变更记录见 [CHANGELOG](../../CHANGELOG.md)。