@fulgurjs/federation 5.7.1 → 5.8.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.
- package/CHANGELOG.md +9 -0
- package/DESIGN.md +3 -0
- package/README.en.md +314 -367
- package/README.md +264 -1186
- package/dist/index.cjs +72 -11
- package/dist/index.js +72 -11
- package/dist/runtime.js +1 -1
- package/docs/API.en.md +328 -0
- package/docs/API.md +913 -0
- package/docs/webpack-mf-/345/257/271/347/205/247/344/270/216/347/274/272/345/217/243.md +64 -37
- package/examples/bridge/react-host/package-lock.json +4 -4
- package/examples/bridge/react-host/package.json +1 -1
- package/examples/bridge/react-remote/package-lock.json +4 -4
- package/examples/bridge/react-remote/package.json +1 -1
- package/examples/bridge/vue-host/package-lock.json +4 -4
- package/examples/bridge/vue-host/package.json +1 -1
- package/examples/bridge/vue-remote/package-lock.json +4 -4
- package/examples/bridge/vue-remote/package.json +1 -1
- package/examples/react/host/package-lock.json +4 -4
- package/examples/react/host/package.json +1 -1
- package/examples/react/remote/package-lock.json +4 -4
- package/examples/react/remote/package.json +1 -1
- package/examples/vue/host/package-lock.json +4 -4
- package/examples/vue/host/package.json +1 -1
- package/examples/vue/remote/package-lock.json +4 -4
- package/examples/vue/remote/package.json +1 -1
- package/package.json +6 -4
package/README.en.md
CHANGED
|
@@ -1,475 +1,422 @@
|
|
|
1
1
|
# @fulgurjs/federation
|
|
2
2
|
|
|
3
|
-
[简体中文](./README.md) | English
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
|
17
|
-
|
|
|
18
|
-
|
|
|
19
|
-
|
|
|
20
|
-
|
|
|
21
|
-
|
|
|
22
|
-
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
## 3. Installation & requirements
|
|
3
|
+
[简体中文](./README.md) | [English](./README.en.md)
|
|
4
|
+
|
|
5
|
+
**Use components, pages and functions from another Vite application.**
|
|
6
|
+
|
|
7
|
+
For example, a main application can load a separately deployed approval page, a Vue host can embed a React sub-app, or several applications can use the same utility module. Each application can live in its own repository and build and deploy separately.
|
|
8
|
+
|
|
9
|
+
This is the usage guide, with examples for **5.7.1**. Signatures, defaults and execution rules are in the [API reference](https://github.com/chenmingye/fulgurjs-federation/blob/master/docs/API.en.md).
|
|
10
|
+
|
|
11
|
+
## Choose what you need
|
|
12
|
+
|
|
13
|
+
| Goal | Use | Example |
|
|
14
|
+
|---|---|---|
|
|
15
|
+
| Load a Vue component in Vue | `remoteComponent` | [Vue examples](https://github.com/chenmingye/fulgurjs-federation/tree/master/examples/vue) |
|
|
16
|
+
| Load a React component in React | `remoteComponent` from `/react` | [React examples](https://github.com/chenmingye/fulgurjs-federation/tree/master/examples/react) |
|
|
17
|
+
| Call a remote JS/TS function | `loadRemote`; React also has `useLoadRemote` | Quick start below |
|
|
18
|
+
| Map several host routes to remote pages | `createHostPages` (Vue) / `createReactHostPages` (React) | [Page demo](https://github.com/chenmingye/fulgurjs-federation/tree/master/demo/pages-cli) |
|
|
19
|
+
| Embed Vue in React, or React in Vue | `defineBridgeApp` + a host bridge component | [Bridge examples](https://github.com/chenmingye/fulgurjs-federation/tree/master/examples/bridge) |
|
|
20
|
+
| Restore a sub-app detail route after refresh | Enable bridge URL sync | [Router demo](https://github.com/chenmingye/fulgurjs-federation/tree/master/demo/bridge-router) |
|
|
21
|
+
| Provide user data or run remote initialization | `AppContext`, optional `setup`/`onSession` | Initialization below |
|
|
22
|
+
| Run React 18 and 19 on the same page | Separate dependency groups and consumers using `shareScope` | [Version isolation demo](https://github.com/chenmingye/fulgurjs-federation/tree/master/demo/react-versions) |
|
|
23
|
+
|
|
24
|
+
Combine these features as needed. **A simple remote component does not require a bridge, page table or login lifecycle.**
|
|
25
|
+
|
|
26
|
+
## Terms in plain language
|
|
27
|
+
|
|
28
|
+
| Term | Meaning |
|
|
29
|
+
|---|---|
|
|
30
|
+
| Host | The application displaying remote content |
|
|
31
|
+
| Remote | The application providing a module |
|
|
32
|
+
| `exposes` | Files the remote allows other applications to load |
|
|
33
|
+
| `remotes` | The remote names and addresses the host uses |
|
|
34
|
+
| `shared` | Dependencies that participate in sharing, such as Vue or React |
|
|
35
|
+
| `singleton` | Adopt one dependency instance within a share scope; this does not make incompatible major versions compatible |
|
|
36
|
+
| `shareScope` | A group of shared dependencies; separate groups can use separate versions |
|
|
37
|
+
| Bridge | A DOM container in which a sub-app manages its own rendering and cleanup |
|
|
38
|
+
| URL sync | Record the sub-app route in the host URL so refresh, sharing and history navigation can restore it |
|
|
39
|
+
|
|
40
|
+
An application can both expose and consume modules.
|
|
41
|
+
|
|
42
|
+
## Install
|
|
43
|
+
|
|
44
|
+
Install in every participating Vite project:
|
|
46
45
|
|
|
47
46
|
```bash
|
|
48
47
|
pnpm add -D @fulgurjs/federation
|
|
48
|
+
# npm projects: npm install -D @fulgurjs/federation
|
|
49
49
|
```
|
|
50
50
|
|
|
51
|
-
-
|
|
52
|
-
-
|
|
53
|
-
-
|
|
54
|
-
- Chrome 108+
|
|
51
|
+
- Supports browser applications using Vue 3, React 18/19, and plain JS/TS modules.
|
|
52
|
+
- Supports Vite 5.1+ within the Vite 5/6/7/8 series. Your framework plugins must also support your chosen Vite version.
|
|
53
|
+
- The plugin requires Node.js ≥18, but **Vite 7/8 require Node.js 20.19+ or 22.12+**. Meet both requirements.
|
|
54
|
+
- Set the build target to `es2022` or newer. Chrome 108+ is the browser baseline; other browsers need corresponding ESM, dynamic import and top-level await support.
|
|
55
|
+
- A pure Vue application needs Vue; a pure React application needs React and react-dom. A cross-framework bridge host installs both frameworks as explained below.
|
|
55
56
|
|
|
56
|
-
|
|
57
|
+
## Quick start: two Vue applications
|
|
57
58
|
|
|
58
|
-
|
|
59
|
+
These steps add federation to **existing Vite + Vue projects**, which retain their own HTML and application entry files.
|
|
59
60
|
|
|
60
|
-
|
|
61
|
+
```text
|
|
62
|
+
remote-vue/ Provides a button and add() function; dev port 5174
|
|
63
|
+
host-vue/ Loads them; dev port 5173
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### 1. Declare remote files
|
|
61
67
|
|
|
62
|
-
|
|
68
|
+
`remote-vue/fulgurjs.config.ts`:
|
|
63
69
|
|
|
64
70
|
```ts
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
71
|
+
import type { FederationOptions } from '@fulgurjs/federation'
|
|
72
|
+
|
|
73
|
+
export default {
|
|
74
|
+
name: 'remote-vue',
|
|
75
|
+
exposes: {
|
|
76
|
+
'./Button': './src/Button.vue',
|
|
77
|
+
'./math': './src/math.ts',
|
|
78
|
+
},
|
|
79
|
+
shared: { vue: { singleton: true, strictVersion: true } },
|
|
80
|
+
} satisfies FederationOptions
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
`remote-vue/src/Button.vue`:
|
|
84
|
+
|
|
85
|
+
```vue
|
|
86
|
+
<script setup lang="ts">
|
|
87
|
+
import { ref } from 'vue'
|
|
88
|
+
defineProps<{ label: string }>()
|
|
89
|
+
const count = ref(0)
|
|
90
|
+
</script>
|
|
70
91
|
|
|
71
|
-
|
|
92
|
+
<template>
|
|
93
|
+
<button @click="count++">{{ label }}: {{ count }}</button>
|
|
94
|
+
</template>
|
|
72
95
|
```
|
|
73
96
|
|
|
74
|
-
|
|
97
|
+
`remote-vue/src/math.ts`:
|
|
75
98
|
|
|
76
|
-
|
|
99
|
+
```ts
|
|
100
|
+
export function add(a: number, b: number): number {
|
|
101
|
+
return a + b
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### 2. Declare the address in the host
|
|
77
106
|
|
|
78
|
-
|
|
107
|
+
`host-vue/fulgurjs.config.ts`:
|
|
79
108
|
|
|
80
109
|
```ts
|
|
81
|
-
// remote: fulgurjs.config.ts
|
|
82
110
|
import type { FederationOptions } from '@fulgurjs/federation'
|
|
83
111
|
|
|
84
112
|
export default {
|
|
85
|
-
name: '
|
|
86
|
-
|
|
87
|
-
'
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
shared: {
|
|
92
|
-
react: { singleton: true },
|
|
93
|
-
'react-dom': { singleton: true },
|
|
113
|
+
name: 'host-vue',
|
|
114
|
+
remotes: {
|
|
115
|
+
'remote-vue': {
|
|
116
|
+
dev: 'http://localhost:5174',
|
|
117
|
+
prod: '/remote-vue',
|
|
118
|
+
},
|
|
94
119
|
},
|
|
120
|
+
shared: { vue: { singleton: true, strictVersion: true } },
|
|
95
121
|
} satisfies FederationOptions
|
|
96
122
|
```
|
|
97
123
|
|
|
98
|
-
|
|
124
|
+
`dev` is the development URL. `prod` is the deployed URL; `/remote-vue` refers to a path on the host origin, not a local filesystem folder.
|
|
99
125
|
|
|
100
|
-
|
|
101
|
-
import { remoteComponent, useLoadRemote, createReactHostPages, remoteSchema } from '@fulgurjs/federation/react'
|
|
102
|
-
import { pages, remotePrefixes } from './src/federation/pages.data'
|
|
126
|
+
### 3. Register the plugin in both applications
|
|
103
127
|
|
|
104
|
-
|
|
105
|
-
// Loading starts on first render. retry rebuilds the load attempt.
|
|
106
|
-
const RemoteButton = remoteComponent<{ label: string; onClick?: () => void }>('remote-react/Button', {
|
|
107
|
-
fallback: <p>Loading remote button…</p>,
|
|
108
|
-
})
|
|
128
|
+
Each project's `vite.config.ts` imports its own federation config:
|
|
109
129
|
|
|
110
|
-
|
|
111
|
-
|
|
130
|
+
```ts
|
|
131
|
+
import { defineConfig } from 'vite'
|
|
132
|
+
import vue from '@vitejs/plugin-vue'
|
|
133
|
+
import federation from '@fulgurjs/federation'
|
|
134
|
+
import fulgurjsConfig from './fulgurjs.config'
|
|
112
135
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
136
|
+
export default defineConfig({
|
|
137
|
+
plugins: [vue(), federation(fulgurjsConfig)],
|
|
138
|
+
build: { target: 'es2022' },
|
|
139
|
+
})
|
|
116
140
|
```
|
|
117
141
|
|
|
118
|
-
|
|
142
|
+
Keep existing aliases, proxies and other settings. Install compatible Vue versions in both applications; `strictVersion` rejects incompatible shared versions.
|
|
119
143
|
|
|
120
|
-
|
|
144
|
+
### 4. Display and call the remote modules
|
|
121
145
|
|
|
122
|
-
|
|
146
|
+
`host-vue/src/App.vue`:
|
|
123
147
|
|
|
124
|
-
|
|
148
|
+
```vue
|
|
149
|
+
<script setup lang="ts">
|
|
150
|
+
import { ref } from 'vue'
|
|
151
|
+
import { loadRemote, remoteComponent } from '@fulgurjs/federation/runtime'
|
|
125
152
|
|
|
126
|
-
|
|
153
|
+
const RemoteButton = remoteComponent('remote-vue/Button')
|
|
154
|
+
const result = ref('Not calculated yet')
|
|
127
155
|
|
|
128
|
-
|
|
156
|
+
async function calculate() {
|
|
157
|
+
try {
|
|
158
|
+
const math = await loadRemote<{ add(a: number, b: number): number }>('remote-vue/math')
|
|
159
|
+
result.value = String(math.add(1, 2))
|
|
160
|
+
} catch (error) {
|
|
161
|
+
result.value = error instanceof Error ? error.message : String(error)
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
</script>
|
|
129
165
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
--require-verified # page-table ↔ remote manifest contract check (CI gate)
|
|
136
|
-
npx fulgurjs doctor --site https://example.com # deployment health check
|
|
166
|
+
<template>
|
|
167
|
+
<RemoteButton label="Remote button" />
|
|
168
|
+
<button @click="calculate">Call remote add()</button>
|
|
169
|
+
<p>{{ result }}</p>
|
|
170
|
+
</template>
|
|
137
171
|
```
|
|
138
172
|
|
|
139
|
-
`
|
|
173
|
+
In `remote-vue/Button`, `remote-vue` matches the host's `remotes` key and `Button` matches the remote's `./Button` expose key. The `./` can be omitted when loading it.
|
|
140
174
|
|
|
141
|
-
|
|
175
|
+
`loadRemote` returns module exports. You still need to call `math.add()` to perform the calculation.
|
|
142
176
|
|
|
143
|
-
###
|
|
177
|
+
### 5. Run both applications
|
|
144
178
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
179
|
+
```bash
|
|
180
|
+
# Terminal one, inside remote-vue
|
|
181
|
+
npm run dev -- --port 5174 --strictPort
|
|
148
182
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
| `error` | `ReactNode` or `(error, retry) => ReactNode`, default built-in Chinese placeholder | shown on load failure **or** subtree render error; the function receives the real error and a working retry |
|
|
153
|
-
| `retries` | `number` (integer 0–10), default follows `loadRemote` (2) | passthrough; invalid values throw at factory call |
|
|
154
|
-
| `timeout` | `number` (ms), default none | adapter-level wait cap for this component load; does **not** cancel the issued shared request; late results never overwrite the settled state and produce no unhandled rejections |
|
|
183
|
+
# Terminal two, inside host-vue
|
|
184
|
+
npm run dev -- --port 5173 --strictPort
|
|
185
|
+
```
|
|
155
186
|
|
|
156
|
-
|
|
157
|
-
- Not built on `React.lazy`: a lazy instance caches its failed promise and an error-boundary reset alone cannot recover; this implementation's retry rebuilds the load attempt (already-cached successful modules are not re-downloaded)
|
|
158
|
-
- Export validation: the default export must be a function/class/`memo`/`forwardRef` component; strings/numbers/empty namespaces fail explicitly
|
|
159
|
-
- `ref` passthrough works for `forwardRef` exports (verified on React 18 and 19)
|
|
160
|
-
- Render exceptions are caught by the built-in boundary and reported separately from network/export errors; the boundary does not catch event-handler or async-callback errors (React semantics)
|
|
161
|
-
- **Session switching:** mounted instances read the current `AppContext.sessionKey` on every render; when the host provides new context and re-renders, the load lifecycle re-runs for the new session on the same instance (no remount, no second React). Same-session re-renders do not reload
|
|
162
|
-
- The built-in placeholder shows error code + real cause + fix + a working 重试 (retry) button
|
|
187
|
+
Open `http://localhost:5173`. The remote button should count clicks, and the calculation should display `3`. pnpm projects can use `pnpm dev` instead.
|
|
163
188
|
|
|
164
|
-
|
|
189
|
+
Complete projects and deployment configuration: [Vue examples](https://github.com/chenmingye/fulgurjs-federation/tree/master/examples/vue).
|
|
165
190
|
|
|
166
|
-
|
|
167
|
-
- Options: `shareScope`, `retries`, `fallbackModule` (explicit degradation — failures return the fallback value instead of writing `error`)
|
|
168
|
-
- Uniform state contract: first load, spec/option/session change and explicit `reload` all enter `data=undefined, error=undefined, loading=true`; the current attempt writes `data` on success or `error` on failure and clears `loading`; stale attempts never write
|
|
169
|
-
- Generation guards: fast A→B switching, late slow responses, consecutive reloads, unmount-during-flight and StrictMode double effects can only write from the latest valid request
|
|
170
|
-
- `reload` clears old data and re-runs the lifecycle (onSession dedup by generation) but never re-downloads cached successful modules; resolves normally (failures surface in `error`, never an unhandled rejection). Unmount invalidates pending effects and reloads; calling a saved reload after unmount starts no request
|
|
171
|
-
- Session-aware: re-runs when `sessionKey` changes; same-session re-renders don't
|
|
191
|
+
## React setup
|
|
172
192
|
|
|
173
|
-
|
|
193
|
+
Use the same configuration structure with these changes:
|
|
174
194
|
|
|
175
|
-
|
|
195
|
+
1. Use `@vitejs/plugin-react` in `vite.config.ts`, followed by `federation(fulgurjsConfig)`.
|
|
196
|
+
2. Expose `./Button` from `./src/Button.tsx`; configure the remote's address in the host.
|
|
197
|
+
3. Both applications use compatible React/renderer versions and share:
|
|
176
198
|
|
|
177
|
-
|
|
199
|
+
```ts
|
|
200
|
+
shared: {
|
|
201
|
+
react: { singleton: true, strictVersion: true },
|
|
202
|
+
'react-dom': { singleton: true, strictVersion: true },
|
|
203
|
+
}
|
|
204
|
+
```
|
|
178
205
|
|
|
179
|
-
|
|
180
|
-
- Display options (same semantics as `remoteComponent`): `fallback`, `error`, `retries`, `timeout`; plus `beforeLoad: () => void | Promise<void>` — runs before **every actual load attempt** (including retries) so the host can refresh context; never at table creation
|
|
181
|
-
- `component<P>(spec)` returns a React component type; the component cache is keyed by spec + login generation (rebuilt only on a new non-empty `sessionKey`; logout → `undefined` does not rebuild). Module-level caching of `component(spec)` results is supported — mounted pages still follow session changes
|
|
182
|
-
- No `keepAliveNames` / no keep-alive promise (Vue-specific); routing is not a runtime dependency — render `component(spec)` output from your router (React Router examples in `examples/react/host`; route params reach remote pages as props)
|
|
183
|
-
- Cross-framework Context: host and remote get the **same Context object** through the same expose instance; the plugin does not auto-bridge arbitrary React Contexts
|
|
206
|
+
Remote `src/Button.tsx`:
|
|
184
207
|
|
|
185
|
-
|
|
208
|
+
```tsx
|
|
209
|
+
import { useState } from 'react'
|
|
186
210
|
|
|
187
|
-
|
|
211
|
+
export default function Button({ label }: { label: string }) {
|
|
212
|
+
const [count, setCount] = useState(0)
|
|
213
|
+
return <button onClick={() => setCount(count + 1)}>{label}: {count}</button>
|
|
214
|
+
}
|
|
215
|
+
```
|
|
188
216
|
|
|
189
|
-
|
|
217
|
+
Host `src/App.tsx`, with a remote configured as `remote-react`:
|
|
190
218
|
|
|
191
|
-
|
|
219
|
+
```tsx
|
|
220
|
+
import { remoteComponent } from '@fulgurjs/federation/react'
|
|
192
221
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
| `initSharing` | `(scopeName?: string) => ShareScopeMap` (default `'default'`) | creates/returns the share scope map (usually called for you by the injected init) |
|
|
198
|
-
| `registerShare` | `(scopeName, name, version, get: () => Promise<any>, opts?: { from?, eager?, loaded? }) => void` | register a provided shared module at runtime; first registration of a version wins |
|
|
199
|
-
| `registerRemote` / `registerRemotes` | `(config: RemoteConfig) => void` / `((list: RemoteConfig[]) => void)` | runtime registration: `{ name, entry, shareScope?, timeout?, retries?, fallback?, breaker?, promise? }`. Promise-based remotes pass `promise: () => Promise<container>` |
|
|
200
|
-
| `registerPlugins` | `(plugins: RuntimePlugin[]) => void` | register runtime plugins; each `init(hooks)` may set `resolveShare`, `beforeLoadRemote({ remote, module })`, `afterLoadRemote({ remote, module, module_ns })`, `onRemoteError({ remote, error })`. Observer-hook failures warn but never break loading |
|
|
201
|
-
| `preloadRemote` | `(spec: string, opts?: { mode?: 'preload' \| 'prefetch' }) => Promise<void>` | manifest-driven preload of entry + expose chunks + CSS; `'prefetch'` = low priority. No lifecycle side effects (setup/onSession are NOT run) |
|
|
202
|
-
| `getContainer` | `(name: string) => Promise<any>` | acquire the initialized container |
|
|
203
|
-
| `getRuntime` | `() => FgRuntime` | the page-level runtime singleton (`globalThis.__FULGURJS_RUNTIME__`) |
|
|
204
|
-
| `parseSpec` | `(spec: string) => { remote, module }` | synchronous spec parsing |
|
|
205
|
-
| `shareScopeMap` | `ShareScopeMap` | live registry (debug surface: `window.__FULGURJS_SCOPE__`) |
|
|
206
|
-
| `unwrapDefault` | `(ns: any) => any` | ESM/CJS default-interop helper |
|
|
207
|
-
| `version` | `string` | plugin/runtime version |
|
|
208
|
-
| `clearSessionState` | `() => void` | invalidate all remotes' session signals and onSession dedup state (called by `clearAppContext`) |
|
|
209
|
-
|
|
210
|
-
Remote-registration config fields: `timeout` (ms, default 15000 — ends the caller's wait, never cancels the issued import), `retries` (0–10, default 2), `fallback: string[]` (spare entry URLs), `breaker: { threshold, resetMs }` (default 5 / 30s).
|
|
211
|
-
|
|
212
|
-
### 8.3 Plugin options — `federation(options)`
|
|
213
|
-
|
|
214
|
-
| Option | Type / default | Notes |
|
|
215
|
-
|---|---|---|
|
|
216
|
-
| `name` | `string`, **required** | container name; unique per page; `/^[a-zA-Z][\w.-]*$/` |
|
|
217
|
-
| `exposes` | `Record<string, string \| { import, name? }>` | key normalized to `./Key`; stable chunk name optional |
|
|
218
|
-
| `remotes` | `Record<string, string \| RemoteEntryConfig \| (() => Promise<any>)>` | string = url or `name@url`; object = `{ external?, dev?, prod?, timeout?, retries?, fallback?, breaker?, shareScope? }`; function = promise-based remote (runtime-register instead) |
|
|
219
|
-
| `shared` | `string[]` or `Record<string, string \| SharedHint>` | see below |
|
|
220
|
-
| `setup` | `string` | module path; must default-export `setup(context)`, optional named `onSession(context)` |
|
|
221
|
-
| `shareScope` | `string`, default `'default'` | default scope for provides |
|
|
222
|
-
| `filename` | `string`, default `'fulgurjs-remoteEntry.js'` | fixed remoteEntry filename |
|
|
223
|
-
| `manifest` | `boolean`, default `true` | emit `fulgurjs-manifest.json` |
|
|
224
|
-
| `dts` | `boolean \| { dir?, mode?: 'source' \| 'shim' }`, default `true` | dev type generation (see §8.6) |
|
|
225
|
-
| `devSharedSelf` | `boolean`, default inferred | pure remotes & dual-role apps: `true` (dev shared rewriting); pure hosts: `false` |
|
|
226
|
-
| `devCorsOrigins` | `'*'` or `string[]` | dev endpoints + server.cors share the policy; explicit user `server.cors` wins |
|
|
227
|
-
| `devFsRoot` | `boolean`, default `true` | dev manifest carries local fsRoot for type direct-connect; `false` → host falls back to `any` stubs |
|
|
228
|
-
| `runtimePlugins` | `string[]` | modules default-exporting a `RuntimePlugin` |
|
|
229
|
-
|
|
230
|
-
`SharedHint` fields: `import` (local specifier or `false` = pure consumer), `packageName` (infer `requiredVersion` from a different package name), `requiredVersion` (semver or `false`), `singleton`, `strictVersion` (default: `true` when a local fallback exists and not singleton, webpack-aligned), `shareKey`, `shareScope`, `eager`, `version`.
|
|
231
|
-
|
|
232
|
-
### 8.4 Lifecycle — `setup` / `onSession`
|
|
222
|
+
// Create once at module scope, not on every render.
|
|
223
|
+
const RemoteButton = remoteComponent<{ label: string }>('remote-react/Button', {
|
|
224
|
+
fallback: <p>Loading…</p>,
|
|
225
|
+
})
|
|
233
226
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
export default async function setup(ctx: { appContext: Record<string, any>; sessionKey?: string; signal: AbortSignal }) {
|
|
237
|
-
// app-level: once per app, before the first business module is returned
|
|
238
|
-
}
|
|
239
|
-
export async function onSession(ctx: { appContext: any; sessionKey: string; signal: AbortSignal }) {
|
|
240
|
-
// session-level: once per host sessionKey (login generation); re-login re-runs, logout invalidates
|
|
227
|
+
export default function App() {
|
|
228
|
+
return <RemoteButton label="Remote React button" />
|
|
241
229
|
}
|
|
242
230
|
```
|
|
243
231
|
|
|
244
|
-
|
|
245
|
-
- `signal` aborts on logout/session change — check `signal.aborted` before writing async results
|
|
246
|
-
- `preloadRemote` / `getContainer` never trigger the lifecycle
|
|
247
|
-
- Remote declares `onSession` → the host **must** provide a non-empty `sessionKey` (MFU-013); never use a token as sessionKey
|
|
248
|
-
- No-setup remotes (plain public components) load normally without any context
|
|
232
|
+
React also imports `loadRemote` and `useLoadRemote` from `/react` for ordinary modules. Complete projects: [React examples](https://github.com/chenmingye/fulgurjs-federation/tree/master/examples/react).
|
|
249
233
|
|
|
250
|
-
|
|
234
|
+
## Embed Vue and React in each other
|
|
251
235
|
|
|
252
|
-
|
|
253
|
-
- `getAppContext()` — read the snapshot (`CC-002` if loaded outside the host federation)
|
|
254
|
-
- `requireAppContext(...keys)` — validated read; missing keys → `CC-001` with got/expected/example
|
|
255
|
-
- `clearAppContext()` — delete context + invalidate session signals/dedup (module and share caches, and completed app-level setup, are preserved). Logout must call it before unmounting authed UI
|
|
256
|
-
- Standard fields: `user`, `getToken()`, `store` (host pinia), `hostApp` (host Vue app), `locale`, `events`, `sessionKey` — plus arbitrary extension keys. Transport snapshot + function references; not reactive
|
|
236
|
+
**A bridge embeds a sub-app with its own component tree. It does not convert a React component into a Vue component.**
|
|
257
237
|
|
|
258
|
-
|
|
238
|
+
For a Vue host embedding React:
|
|
259
239
|
|
|
260
|
-
|
|
261
|
-
- Precise track: add `"paths": { "<remote>/*": ["<typesDir>/<remote>.d/*"] }` to the app's **effective TS context** — `tsconfig.json` itself, its `extends` chain, or a referenced sub-project whose `include` covers the app source / types output dir. Standalone `tsconfig.test.json`, `tsconfig.node.json` (vite.config only) and other unrelated configs do not affect the decision; imports then resolve through forwarder modules to **source-level types** (wrong props/arguments fail compilation). Remotes covered by paths automatically skip their loose declaration to avoid shadowing
|
|
240
|
+
1. React remote `src/bridge.tsx`:
|
|
262
241
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
- `dts: false` stops generation without deleting existing output; `dts.dir` relocates; `mode: 'shim'` gives loose IDE-clean placeholders
|
|
266
|
-
- Precise track requires the host and remote to share a filesystem (same-machine dev); verified bounds: React 18.0.0–19.x with matching @types
|
|
242
|
+
```tsx
|
|
243
|
+
import { defineBridgeApp } from '@fulgurjs/federation/react'
|
|
267
244
|
|
|
268
|
-
|
|
245
|
+
export default defineBridgeApp((props) => (
|
|
246
|
+
<section>React sub-app: {String(props.message ?? '')}</section>
|
|
247
|
+
))
|
|
248
|
+
```
|
|
269
249
|
|
|
270
|
-
|
|
250
|
+
2. Add `exposes: { './bridge': './src/bridge.tsx' }` to the remote config.
|
|
251
|
+
3. Configure the remote address in the Vue host, then use:
|
|
271
252
|
|
|
272
|
-
|
|
253
|
+
```vue
|
|
254
|
+
<script setup lang="ts">
|
|
255
|
+
import { createVueBridgeApp } from '@fulgurjs/federation/bridge/vue'
|
|
256
|
+
const RemoteApp = createVueBridgeApp<{ message: string }>('remote-react/bridge')
|
|
257
|
+
</script>
|
|
273
258
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
React sub-app @fulgurjs/federation/react -> defineBridgeApp (zero Vue; react-dom/client loads at mount time)
|
|
278
|
-
bridge host @fulgurjs/federation/bridge/vue -> createVueBridgeApp (recommended for Vue hosts; zero React)
|
|
279
|
-
@fulgurjs/federation/bridge/react -> createReactBridgeApp (recommended for React hosts; zero Vue)
|
|
280
|
-
@fulgurjs/federation/bridge -> aggregate (kept for compatibility; dev native ESM executes both host adapters)
|
|
259
|
+
<template>
|
|
260
|
+
<RemoteApp :app-props="{ message: 'From Vue host' }" />
|
|
261
|
+
</template>
|
|
281
262
|
```
|
|
282
263
|
|
|
283
|
-
|
|
264
|
+
A cross-framework host installs and shares `vue`, `react` and `react-dom`. The child installs and shares its own framework. React and react-dom must be compatible; multiple React majors need separate dependency groups and consumers, as shown in the isolation demo.
|
|
284
265
|
|
|
285
|
-
|
|
266
|
+
In the other direction, use `createReactBridgeApp` in the React host. The Vue child uses `defineBridgeApp` from `/runtime` and returns a `createApp(...)` application.
|
|
286
267
|
|
|
287
|
-
|
|
268
|
+
Remember:
|
|
288
269
|
|
|
289
|
-
|
|
270
|
+
- `appProps` is a snapshot taken at mount. Replacing top-level fields later does not update the child. Pass stable callbacks/shared stores for live data, or change the component `key` to remount.
|
|
271
|
+
- Separate component trees do not inherit Context, provide/inject or routers. Pass or install what is needed explicitly.
|
|
272
|
+
- Use `remoteComponent` for a same-framework component; use a bridge for a sub-app.
|
|
290
273
|
|
|
291
|
-
|
|
292
|
-
// Vue sub-app src/bridge.ts
|
|
293
|
-
import { createApp } from 'vue'
|
|
294
|
-
import { createMemoryHistory, createRouter } from 'vue-router'
|
|
295
|
-
import { defineBridgeApp } from '@fulgurjs/federation/runtime'
|
|
296
|
-
export default defineBridgeApp((props) => {
|
|
297
|
-
const app = createApp(App, props)
|
|
298
|
-
app.use(createRouter({ history: createMemoryHistory(), routes }))
|
|
299
|
-
return app
|
|
300
|
-
})
|
|
301
|
-
```
|
|
274
|
+
Complete bidirectional setup and login/cleanup flows: [bridge examples](https://github.com/chenmingye/fulgurjs-federation/tree/master/examples/bridge).
|
|
302
275
|
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
276
|
+
## Keep child routes in the browser URL
|
|
277
|
+
|
|
278
|
+
Bridging does not change the host URL by default. Enable URL sync to map:
|
|
279
|
+
|
|
280
|
+
```text
|
|
281
|
+
Host /approval/list → Child /list
|
|
282
|
+
Host /approval/detail/42 → Child /detail/42
|
|
308
283
|
```
|
|
309
284
|
|
|
310
|
-
|
|
311
|
-
- `mount(el, props?): void | Promise<void>` — returning `void` means the first root commit completed synchronously (Vue); a Promise keeps the host pending until the first root commit completes (React uses a built-in commit probe; `root.render()` returning does **not** count as success). Failure before the first commit must throw/reject (host turns it into `MFU-016`, `details.phase: 'mount'`) after cleaning up any created root.
|
|
312
|
-
- `unmount(el): void` — synchronously invalidates the current generation for that container and cleans up; unknown containers are a no-op. Unmounting while pending immediately invalidates the in-flight generation: late results must not revive DOM, overwrite host state, or produce unhandled rejections. An `unmount` throw is reported as `MFU-016` (`phase: 'unmount'`); the container's cleanup state is uncertain, and the plugin **permanently blocks that container**: neither the in-page retry nor a session change will mount a new instance there (the default placeholder removes its retry button), so a full page reload is the only recovery; audit leftover resources (subscriptions/timers/global side effects) honestly.
|
|
313
|
-
- Contract instances are keyed **per container element**; double-mount on the same container is rejected (`MFU-016`).
|
|
314
|
-
- Errors inside the sub-app after the first commit belong to **the sub-app's own error boundary** — host boundaries cannot catch cross-root render errors.
|
|
285
|
+
Configure both sides:
|
|
315
286
|
|
|
316
|
-
|
|
287
|
+
1. The host router must handle all child paths under `/approval` without unmounting the child on each detail navigation.
|
|
288
|
+
2. Pass `routing` to the host bridge component, including `basePath: '/approval'` and the host navigation adapter.
|
|
289
|
+
3. The child declares `defineBridgeApp(..., { routing: true })` and connects a controlled memory router.
|
|
317
290
|
|
|
318
|
-
|
|
319
|
-
// Vue host
|
|
320
|
-
import { createVueBridgeApp } from '@fulgurjs/federation/bridge/vue'
|
|
321
|
-
const RemoteReactApp = createVueBridgeApp('bridge-react-remote/bridge', {
|
|
322
|
-
retries: 1,
|
|
323
|
-
getContext: () => getLatestHostContext(), // your own synchronous pure getter
|
|
324
|
-
})
|
|
325
|
-
// <RemoteReactApp :session-key="loginKey" :app-props="{ userId, onReady }" />
|
|
326
|
-
```
|
|
291
|
+
Vue uses `createVueBridgeNavigation` / `connectVueBridgeRouter`; React uses `createReactBridgeNavigation` / `createReactBridgeRouter`. React hosts need a data router (`createBrowserRouter` or `createHashRouter`), not `BrowserRouter`. Built-in adapters support Vue Router 4 and React Router ≥6.11.
|
|
327
292
|
|
|
328
|
-
|
|
329
|
-
// React host
|
|
330
|
-
import { createReactBridgeApp } from '@fulgurjs/federation/bridge/react'
|
|
331
|
-
const RemoteVueApp = createReactBridgeApp('bridge-vue-remote/bridge', { getContext: () => getLatestHostContext() })
|
|
332
|
-
// <RemoteVueApp sessionKey={loginKey} appProps={{ userId, onReady }} />
|
|
333
|
-
```
|
|
293
|
+
Refresh, shared links and browser history restore the route, **not form contents or business data**. See [routing API](https://github.com/chenmingye/fulgurjs-federation/blob/master/docs/API.en.md#url-sync) and the runnable [router demo](https://github.com/chenmingye/fulgurjs-federation/tree/master/demo/bridge-router).
|
|
334
294
|
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
| Component props | `appProps: P` + `sessionKey?: string \| null` (control prop, never mixed into business props) | same |
|
|
339
|
-
| Error placeholder | Chinese diagnostic (code + root cause + fix) with retry / full-reload buttons | same |
|
|
295
|
+
## User data and remote initialization
|
|
296
|
+
|
|
297
|
+
These features are optional. A plain button or utility module does not need them.
|
|
340
298
|
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
299
|
+
| Need | API | When |
|
|
300
|
+
|---|---|---|
|
|
301
|
+
| Provide user, token getter, store, etc. | `provideAppContext` | Host supplies them before loading business modules |
|
|
302
|
+
| Read host values | `getAppContext` / `requireAppContext` | Called by remote business code |
|
|
303
|
+
| Initialize a remote once | Default export in configured `setup` file | Before the first business `loadRemote('remote/module')` returns |
|
|
304
|
+
| Synchronize permissions after login/account changes | Named `onSession` export in the same file | Deduplicated by `sessionKey` |
|
|
305
|
+
| Clear account context on logout | `clearAppContext` | Host logout flow; host also removes private pages/caches |
|
|
345
306
|
|
|
346
|
-
|
|
307
|
+
`sessionKey` identifies a login attempt; it is **not a token or authorization credential**. Generate a new value on login/account change; token refresh alone retains it.
|
|
347
308
|
|
|
348
|
-
|
|
309
|
+
A bridge can read current data using `getContext`. Controlled `sessionKey: null` means logged out: unmount and stop loading. Omitting the key disables controlled session switching.
|
|
349
310
|
|
|
350
|
-
|
|
311
|
+
Only a configured `setup` file participates in initialization. `preloadRemote` fetches resources without running setup/onSession. Async initialization must check `context.signal.aborted` before writing state, so late responses do not restore old-account data.
|
|
351
312
|
|
|
352
|
-
|
|
313
|
+
See the [API reference](https://github.com/chenmingye/fulgurjs-federation/blob/master/docs/API.en.md#context).
|
|
353
314
|
|
|
354
|
-
|
|
355
|
-
Vue: `defineBridgeApp(async (props, ctx) => { const router = createRouter({ history: createMemoryHistory(), routes }); await connectVueBridgeRouter(ctx.routing!, router).ready; ... app.use(router); return app }, { routing: true })` (await ready BEFORE `app.use(router)` — the install-time initial navigation would otherwise override the deep-link location).
|
|
356
|
-
React: `createReactBridgeRouter(ctx.routing!, routes).element` — `createMemoryRouter`-based; `Link`/`useNavigate` work unmodified.
|
|
315
|
+
## Several remote pages
|
|
357
316
|
|
|
358
|
-
|
|
317
|
+
Maintain a page table and pass it to `createHostPages` (Vue) or `createReactHostPages` (React). These helpers resolve modules, cache loading components and provide loading/error states. **They do not create your host Router.**
|
|
359
318
|
|
|
360
|
-
|
|
319
|
+
The table records the host `route` and the remote expose `spec` (omit `./` and do not repeat the remote name); `remotePrefixes` selects the remote. For example, `/shop/home`, `spec: 'pages/Home'` and `remotePrefixes: { '/shop': 'shop' }` resolve to `shop/pages/Home`. Vue can use KeepAlive for component state; React has no equivalent keep-alive promise here.
|
|
361
320
|
|
|
362
|
-
|
|
321
|
+
See [page API](https://github.com/chenmingye/fulgurjs-federation/blob/master/docs/API.en.md#pages) and [page demo](https://github.com/chenmingye/fulgurjs-federation/tree/master/demo/pages-cli).
|
|
363
322
|
|
|
364
|
-
##
|
|
323
|
+
## Build and deploy
|
|
365
324
|
|
|
366
|
-
|
|
367
|
-
|---|---|
|
|
368
|
-
| `fulgurjs-remoteEntry.js` (fixed filename, content changes every build) | **`no-cache`** |
|
|
369
|
-
| content-hashed chunks / CSS | `immutable` long cache |
|
|
370
|
-
| `fulgurjs-manifest.json` | `no-cache` (consumed by `preloadRemote` / `check-pages` / `doctor`) |
|
|
371
|
-
| dev endpoints `/@fulgurjs-entry.js` / `/@fulgurjs-manifest.json` | `no-cache`, CORS per `devCorsOrigins` |
|
|
325
|
+
Build each application separately with its own `npm run build`. The remote produces `fulgurjs-remoteEntry.js` and `fulgurjs-manifest.json` by default. The host locates them through `prod`.
|
|
372
326
|
|
|
373
|
-
|
|
327
|
+
Check these settings:
|
|
374
328
|
|
|
375
|
-
|
|
329
|
+
- Remote deployment `/remote-vue/` → remote Vite `base: '/remote-vue/'` and host `prod: '/remote-vue'`.
|
|
330
|
+
- HTML, remoteEntry and manifest use `Cache-Control: no-cache`; content-hashed chunks can use long-lived caching.
|
|
331
|
+
- SPA routes support refresh; missing resource URLs return 404 rather than HTML.
|
|
332
|
+
- Cross-origin deployments need production CORS headers; dev settings do not configure the production server.
|
|
333
|
+
- Keep chunks still referenced by old pages available during releases, or use a deployment flow that avoids mixed versions.
|
|
376
334
|
|
|
377
|
-
|
|
378
|
-
- `window.__FULGURJS_INFO__` — per-remote status/latency/errors + `errors` log
|
|
379
|
-
- `DEBUG=fulgurjs:*` — controlled pipeline diagnostics (off by default)
|
|
380
|
-
- Runtime diagnostics are emitted in Chinese by design (language policy); codes are stable identifiers listed below
|
|
335
|
+
Deployment examples: [Vue](https://github.com/chenmingye/fulgurjs-federation/blob/master/examples/vue/README.md) / [React](https://github.com/chenmingye/fulgurjs-federation/blob/master/examples/react/README.md).
|
|
381
336
|
|
|
382
|
-
##
|
|
337
|
+
## Handle failures
|
|
383
338
|
|
|
384
|
-
|
|
|
339
|
+
| Symptom | Check | Recovery |
|
|
385
340
|
|---|---|---|
|
|
386
|
-
|
|
|
387
|
-
|
|
|
388
|
-
|
|
|
389
|
-
| |
|
|
390
|
-
| |
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
| | `MFU-002` | remoteEntry self-reported name mismatch |
|
|
413
|
-
| | `MFU-003` | strictVersion requirement not satisfied |
|
|
414
|
-
| | `MFU-004` | shared module missing with no local fallback |
|
|
415
|
-
| | `MFU-005` | same container re-initialized with a different share scope |
|
|
416
|
-
| | `MFU-006` | requested module not exposed by the remote |
|
|
417
|
-
| | `MFU-007` | preload failed (non-blocking) |
|
|
418
|
-
| | `MFU-008` | unknown remote |
|
|
419
|
-
| | `MFU-009` | loaded module has no exports at all |
|
|
420
|
-
| | `MFU-010` | reused singleton version doesn't satisfy the consumer requirement (warn-once) |
|
|
421
|
-
| | `MFU-011` | setup entry export shape invalid |
|
|
422
|
-
| | `MFU-012` | setup/onSession threw (retryable; only the failed stage resets) |
|
|
423
|
-
| | `MFU-013` | onSession declared but host sessionKey missing |
|
|
424
|
-
| | `MFU-014` | setup/onSession synchronously re-loading the same remote (deadlock guard) |
|
|
425
|
-
| | `MFU-015` | bridge contract invalid (`./bridge` default export missing non-function mount/unmount; fix points to `defineBridgeApp`) |
|
|
426
|
-
| | `MFU-016` | bridge preparation or lifecycle failure (`details.phase` = getContext/mount/unmount; cause keeps the sub-app's original error) |
|
|
427
|
-
| | `MFU-017` | bridge session mismatch (controlled sessionKey vs AppContext / illegal value / page-level single-session conflict) |
|
|
428
|
-
| MFU | `MFU-030` | Bridge URL-sync config invalid / prefix conflict (illegal basePath: empty, root, query/hash/wildcard; overlapping active prefixes) |
|
|
429
|
-
| MFU | `MFU-031` | Bridge routing protocol missing / channel destroyed (sub-app not declared with `{ routing: true }`; disposed channel reused) |
|
|
430
|
-
| MFU | `MFU-032` | Bridge illegal navigation (target escaping its own prefix, illegal `go` argument, request on a dead channel) |
|
|
431
|
-
| MFU | `MFU-033` | Bridge routing preparation/sync failed (redirect limit or navigation exception, chain/cause attached; no silent fallback to memory) |
|
|
432
|
-
| CC | `CC-001` | AppContext required key missing (got/expected/example) |
|
|
433
|
-
| | `CC-002` | runtime singleton unavailable (standalone remote page) |
|
|
434
|
-
|
|
435
|
-
## 12. Boundaries (explicitly not supported)
|
|
436
|
-
|
|
437
|
-
- Support covers **browser-client** federation for Vue 3 and React 18–19. Not supported: SSR, React Server Components, Next.js full-stack, React Native, Node-side remote loading. **Cross-framework boundary (5.3.0+)**: sub-app-level embedding is supported (§8.7 `/bridge`); direct component-level Vue↔React rendering in one tree is not (that is the product of framework-conversion libraries). Pure single-framework projects keep zero cross-dependency
|
|
438
|
-
- **Bridge isolation boundary (declared honestly in §8.7)**: bridging isolates only the mount/unmount edge of the two component trees — no browser realm isolation. Remote global CSS, `body`/`html` styles, global variables, and DOM rendered outside the container via React Portal / Vue Teleport still affect the host; `unmount` cannot revoke CSS the browser already loaded. Sub-app internal errors do not bubble into host error boundaries (cross-root). Sub-app routing defaults to memory mode; explicit URL sync exists since 5.4.0 (§8.8) — when it is not enabled, refreshing does not restore the sub-app's internal path
|
|
439
|
-
- React side does not promise component keep-alive (`keepAliveNames` is Vue-only); re-opened pages still reuse downloaded modules
|
|
440
|
-
- Cross-origin Fast Refresh: remote React components update via the remote dev server's HMR push; after a cold start the first round often needs a host refresh — component-state retention across the federation boundary is not promised
|
|
441
|
-
- Not compatible with originjs `virtual:__federation__` legacy imports
|
|
442
|
-
- No browser DevTools extension (the `window.__FULGURJS_*` surfaces serve debugging)
|
|
443
|
-
|
|
444
|
-
## 13. Documentation & examples
|
|
445
|
-
|
|
446
|
-
- [Migration guide (Chinese)](https://github.com/chenmingye/fulgurjs-federation/blob/master/docs/迁移指南.md) — a real qiankun → federation migration (seven steps + acceptance checklist)
|
|
447
|
-
- [webpack MF comparison & gaps (Chinese)](https://github.com/chenmingye/fulgurjs-federation/blob/master/docs/webpack-mf-对照与缺口.md)
|
|
448
|
-
- [Sandbox boundary audit (Chinese)](https://github.com/chenmingye/fulgurjs-federation/blob/master/docs/沙箱边界审计.md)
|
|
449
|
-
- [`DESIGN.md`](https://github.com/chenmingye/fulgurjs-federation/blob/master/DESIGN.md) — architecture and alignment tables
|
|
450
|
-
- Examples: [`examples/vue/{host,remote}`](./examples) + [`examples/react/{host,remote}`](./examples) + [`examples/bridge/*`](./examples) — copy-and-run projects, registry-installable (see the examples entry page)
|
|
451
|
-
|
|
452
|
-
## 14. Development & testing
|
|
341
|
+
| Remote unavailable | Server, address, CORS | Timeout/retry/error UI; optional backup entry or fallback module |
|
|
342
|
+
| Module missing | remotes name and exposes key | Fix the name and retry |
|
|
343
|
+
| Shared version incompatible | Installed versions, requiredVersion, strictVersion, scope | Align or isolate versions |
|
|
344
|
+
| Static dependency remains failed after service recovery | Browser may retain the failed dependency URL | User-initiated refresh preserves the current address |
|
|
345
|
+
| Child unmount fails | Child cleanup, timers and subscriptions | Container stays blocked; refresh and fix cleanup |
|
|
346
|
+
|
|
347
|
+
`remoteComponent` and bridge components provide default error UI. Direct `loadRemote` calls and React `useLoadRemote` require application error handling. An explicit `fallbackModule` does not repair the original remote.
|
|
348
|
+
|
|
349
|
+
Errors include a code, cause and fix. See [error codes](https://github.com/chenmingye/fulgurjs-federation/blob/master/docs/API.en.md#error-codes).
|
|
350
|
+
|
|
351
|
+
## Vite 8 and support boundaries
|
|
352
|
+
|
|
353
|
+
**Supports Vite 8 development and production. The earlier large-application startup hang has been fixed and relevant regression tests pass.**
|
|
354
|
+
|
|
355
|
+
Two practical details:
|
|
356
|
+
|
|
357
|
+
- A first dev visit may reload while Vite prepares newly discovered dependencies. Wait for optimization before judging stable behavior. This is not a production behavior on every visit.
|
|
358
|
+
- Some shared scenarios fetch an unused local library copy. One singleton scope still uses one instance; explicitly isolated React 18/19 scopes may use one each. Downloaded file count and active instance count are different.
|
|
359
|
+
|
|
360
|
+
Not provided: SSR/RSC, Node-side federation, React Native, automatic JS/CSS isolation, webpack `script/var` artifact interoperability, component-type conversion, automatic multi-level bridge routing proxies or cross-window route sync. Global CSS/variables can affect the host; children need their own internal error handling.
|
|
361
|
+
|
|
362
|
+
See the [capability comparison](https://github.com/chenmingye/fulgurjs-federation/blob/master/docs/webpack-mf-对照与缺口.md) for detailed boundaries and differences from webpack.
|
|
363
|
+
|
|
364
|
+
## Debugging, types and CLI
|
|
365
|
+
|
|
366
|
+
Run in the application directory:
|
|
453
367
|
|
|
454
368
|
```bash
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
pnpm --dir e2e exec playwright test --list # inspect unique cases and project ownership
|
|
464
|
-
node e2e/scripts/pack-smoke.mjs # local tarball consumer checks; not registry acceptance
|
|
465
|
-
node e2e/scripts/react-types-check.mjs # dual-track dev types + negative matrix
|
|
466
|
-
node e2e/scripts/react-negative-check.mjs # N08/N10/N11 negative checks
|
|
467
|
-
bash e2e/scripts/prod-setup.sh # build all fixtures + isolated NGINX
|
|
369
|
+
npx fulgurjs init
|
|
370
|
+
npx fulgurjs explain
|
|
371
|
+
|
|
372
|
+
# Optional: validate a configured host page table
|
|
373
|
+
npx fulgurjs check-pages --site http://localhost:5173
|
|
374
|
+
|
|
375
|
+
# After deployment under /remote-vue/, substitute your actual site:
|
|
376
|
+
npx fulgurjs doctor --base https://your-site.example --apps remote-vue
|
|
468
377
|
```
|
|
469
378
|
|
|
470
|
-
|
|
379
|
+
For `doctor`, `--base` is the site URL and `--apps` lists deployment subdirectories: the example checks `/remote-vue/`. It does not infer a different development port from a container name.
|
|
380
|
+
|
|
381
|
+
`init` creates a federation config template, not a full application, router or Nginx configuration. `check-pages` compares the page table with remote exposes; an unreachable remote is reported as unverified.
|
|
382
|
+
|
|
383
|
+
Remote dev types are generated by default. Accessible source provides more precise mapping; inaccessible source produces `any` declarations without precise checks/completion. Set `dts: false` to disable generation. See the reference for details.
|
|
384
|
+
|
|
385
|
+
Advanced diagnostics use `window.__FULGURJS_SCOPE__`, `window.__FULGURJS_INFO__` and `FULGURJS_DEBUG`. Normal integration does not require editing these objects.
|
|
386
|
+
|
|
387
|
+
## API reference
|
|
388
|
+
|
|
389
|
+
Use the current reference rather than guessing signatures from old task documents:
|
|
390
|
+
|
|
391
|
+
- [Plugin options and defaults](https://github.com/chenmingye/fulgurjs-federation/blob/master/docs/API.en.md#plugin-options)
|
|
392
|
+
- [Runtime loading, registration and hooks](https://github.com/chenmingye/fulgurjs-federation/blob/master/docs/API.en.md#runtime)
|
|
393
|
+
- [Bridge props, sessions and cleanup](https://github.com/chenmingye/fulgurjs-federation/blob/master/docs/API.en.md#bridge)
|
|
394
|
+
- [URL sync and navigation](https://github.com/chenmingye/fulgurjs-federation/blob/master/docs/API.en.md#url-sync)
|
|
395
|
+
- [Chinese API reference](https://github.com/chenmingye/fulgurjs-federation/blob/master/docs/API.md)
|
|
396
|
+
|
|
397
|
+
### When an AI implements your integration
|
|
398
|
+
|
|
399
|
+
Specify the framework, whether you need a component or sub-app, remote URLs/expose names, and whether login switching or URL sync is required. Have it read the guide and relevant API section first, preserve the existing Vite configuration, check installed versions and use the correct browser entry. It should not invent configuration fields. Verify mounting, interaction and error handling; URL sync also needs deep-link refresh, history and cancellation checks.
|
|
400
|
+
|
|
401
|
+
## Documentation
|
|
402
|
+
|
|
403
|
+
- [Demo catalog](https://github.com/chenmingye/fulgurjs-federation/blob/master/demo/README.md): setup and runnable scenarios.
|
|
404
|
+
- [Copy-and-run templates](https://github.com/chenmingye/fulgurjs-federation/tree/master/templates): five pnpm-workspace templates (Vue×Vue, React×React, both cross-framework bridge directions, and a full showcase). Copy a folder, then `pnpm install && pnpm dev`.
|
|
405
|
+
- [Migration guide](https://github.com/chenmingye/fulgurjs-federation/blob/master/docs/迁移指南.md).
|
|
406
|
+
- [CHANGELOG](https://github.com/chenmingye/fulgurjs-federation/blob/master/CHANGELOG.md): changes and migration requirements.
|
|
407
|
+
- [Acceptance records](https://github.com/chenmingye/fulgurjs-federation/blob/master/docs/整夜全量验收报告-20261004.md): overnight acceptance on two real MES business projects (fresh SVN copies), covering dev, production, fault recovery and HMR, plus production-build notes for large Vite 6 apps (that round required disabling `manualChunks`; **fixed in 5.8.0 — keep your own `manualChunks`, shared bodies are isolated into `fulgurjs-provider-*` chunks automatically**). Historical record: [20261002 demo acceptance](https://github.com/chenmingye/fulgurjs-federation/blob/master/docs/完整Demo展示与全面复测-验收报告-20261002.md) — historical results are not a substitute for testing your application.
|
|
408
|
+
|
|
409
|
+
## Development and testing
|
|
410
|
+
|
|
411
|
+
These commands develop **this plugin repository**; ordinary consumers do not need them:
|
|
412
|
+
|
|
413
|
+
```bash
|
|
414
|
+
pnpm --dir packages/plugin install
|
|
415
|
+
pnpm --dir packages/plugin build
|
|
416
|
+
pnpm test:unit
|
|
417
|
+
```
|
|
471
418
|
|
|
472
|
-
|
|
419
|
+
See [CONTRIBUTING](https://github.com/chenmingye/fulgurjs-federation/blob/master/CONTRIBUTING.md) for fixture installation and browser test prerequisites. CI checks builds, types, unit tests, installed packages and browser scenarios across multiple Vite versions. Counts come from the corresponding run.
|
|
473
420
|
|
|
474
421
|
## License
|
|
475
422
|
|