@fulgurjs/federation 6.8.7 → 6.9.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 (139) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/README.en.md +3 -0
  3. package/README.md +3 -0
  4. package/dist/application-core-BuhXQmLF.d.cts +16 -0
  5. package/dist/application-core-DWI3eKme.d.ts +16 -0
  6. package/dist/bridge-app-react.cjs +177 -9
  7. package/dist/bridge-app-react.d.cts +15 -3
  8. package/dist/bridge-app-react.d.ts +15 -3
  9. package/dist/bridge-app-react.js +101 -9
  10. package/dist/bridge-app-vue.cjs +138 -12
  11. package/dist/bridge-app-vue.d.cts +20 -5
  12. package/dist/bridge-app-vue.d.ts +20 -5
  13. package/dist/bridge-app-vue.js +62 -12
  14. package/dist/bridge-host-react.d.cts +1 -1
  15. package/dist/bridge-host-react.d.ts +1 -1
  16. package/dist/bridge-host-vue.d.cts +1 -1
  17. package/dist/bridge-host-vue.d.ts +1 -1
  18. package/dist/chunk-6OB47FSR.js +81 -0
  19. package/dist/cli.js +349 -23
  20. package/dist/index.cjs +7 -6
  21. package/dist/index.js +7 -6
  22. package/dist/react-adapter.d.cts +1 -1
  23. package/dist/react-adapter.d.ts +1 -1
  24. package/dist/react.d.ts +29 -4
  25. package/dist/react.js +1 -0
  26. package/dist/{remote-types-xf1B6_pK.d.ts → remote-types-COmBhjRc.d.ts} +1 -1
  27. package/dist/{remote-types-58hdbx6x.d.cts → remote-types-CStGOJwu.d.cts} +1 -1
  28. package/dist/runtime.js +1 -1
  29. package/dist/vue-adapter.d.cts +1 -1
  30. package/dist/vue-adapter.d.ts +1 -1
  31. package/dist/vue-store.cjs +40 -0
  32. package/dist/vue-store.d.cts +4 -0
  33. package/dist/vue-store.d.ts +4 -0
  34. package/dist/vue-store.js +15 -0
  35. package/dist/vue.d.ts +37 -6
  36. package/dist/vue.js +2 -0
  37. package/docs/en/reference/api.md +38 -2
  38. package/docs/en/reference/types.md +27 -0
  39. package/docs/zh/reference/api.md +46 -2
  40. package/docs/zh/reference/types.md +27 -0
  41. package/examples/templates/README.md +3 -0
  42. package/examples/templates/react-host-vue-remote/README.md +24 -0
  43. package/examples/templates/react-host-vue-remote/package.json +2 -1
  44. package/examples/templates/react-host-vue-remote/pnpm-lock.yaml +7 -7
  45. package/examples/templates/react-host-vue-remote/pnpm-workspace.yaml +1 -1
  46. package/examples/templates/react-host-vue-remote/react-host/package.json +1 -1
  47. package/examples/templates/react-host-vue-remote/react-host/src/application.tsx +62 -0
  48. package/examples/templates/react-host-vue-remote/react-host/src/main.tsx +2 -62
  49. package/examples/templates/react-host-vue-remote/scripts/prod.mjs +101 -0
  50. package/examples/templates/react-host-vue-remote/vue-remote/README.md +17 -16
  51. package/examples/templates/react-host-vue-remote/vue-remote/fulgurjs.config.ts +2 -2
  52. package/examples/templates/react-host-vue-remote/vue-remote/package.json +1 -1
  53. package/examples/templates/react-host-vue-remote/vue-remote/src/AboutPage.vue +1 -0
  54. package/examples/templates/react-host-vue-remote/vue-remote/src/App.vue +15 -5
  55. package/examples/templates/react-host-vue-remote/vue-remote/src/HomePage.vue +1 -0
  56. package/examples/templates/react-host-vue-remote/vue-remote/src/application.ts +19 -0
  57. package/examples/templates/react-host-vue-remote/vue-remote/src/main.ts +2 -15
  58. package/examples/templates/react-react/README.md +25 -1
  59. package/examples/templates/react-react/host/package.json +1 -1
  60. package/examples/templates/react-react/host/src/application.tsx +33 -0
  61. package/examples/templates/react-react/host/src/main.tsx +3 -32
  62. package/examples/templates/react-react/package.json +2 -1
  63. package/examples/templates/react-react/pnpm-lock.yaml +7 -7
  64. package/examples/templates/react-react/pnpm-workspace.yaml +1 -1
  65. package/examples/templates/react-react/remote/package.json +1 -1
  66. package/examples/templates/react-react/remote/src/application.tsx +11 -0
  67. package/examples/templates/react-react/remote/src/main.tsx +3 -10
  68. package/examples/templates/react-react/scripts/prod.mjs +101 -0
  69. package/examples/templates/showcase/README.md +35 -7
  70. package/examples/templates/showcase/package.json +2 -1
  71. package/examples/templates/showcase/pnpm-lock.yaml +11 -11
  72. package/examples/templates/showcase/pnpm-workspace.yaml +1 -1
  73. package/examples/templates/showcase/react-host/package.json +1 -1
  74. package/examples/templates/showcase/react-host/src/application.tsx +28 -0
  75. package/examples/templates/showcase/react-host/src/demo-log.ts +5 -8
  76. package/examples/templates/showcase/react-host/src/main.tsx +2 -33
  77. package/examples/templates/showcase/react-host/src/routing.ts +2 -2
  78. package/examples/templates/showcase/react-remote/fulgurjs.config.ts +1 -1
  79. package/examples/templates/showcase/react-remote/package.json +1 -1
  80. package/examples/templates/showcase/react-remote/src/ChildLayout.tsx +3 -2
  81. package/examples/templates/showcase/react-remote/src/{bridge.tsx → application.tsx} +21 -21
  82. package/examples/templates/showcase/react-remote/src/child-bus.ts +23 -23
  83. package/examples/templates/showcase/react-remote/src/main.tsx +2 -18
  84. package/examples/templates/showcase/react-remote/src/pages/Locked.tsx +2 -1
  85. package/examples/templates/showcase/react-remote/src/pages/OrderDetail.tsx +2 -1
  86. package/examples/templates/showcase/react-remote/src/pages/OrderList.tsx +2 -1
  87. package/examples/templates/showcase/scripts/prod.mjs +101 -0
  88. package/examples/templates/showcase/vue-host/package.json +1 -1
  89. package/examples/templates/showcase/vue-host/src/application.ts +28 -0
  90. package/examples/templates/showcase/vue-host/src/demo-log.ts +4 -7
  91. package/examples/templates/showcase/vue-host/src/main.ts +2 -30
  92. package/examples/templates/showcase/vue-host/src/routing.ts +2 -2
  93. package/examples/templates/showcase/vue-remote/fulgurjs.config.ts +1 -1
  94. package/examples/templates/showcase/vue-remote/package.json +1 -1
  95. package/examples/templates/showcase/vue-remote/src/ChildLayout.vue +3 -2
  96. package/examples/templates/showcase/vue-remote/src/{bridge.ts → application.ts} +10 -13
  97. package/examples/templates/showcase/vue-remote/src/child-bus.ts +23 -23
  98. package/examples/templates/showcase/vue-remote/src/main.ts +2 -16
  99. package/examples/templates/showcase/vue-remote/src/pages/Locked.vue +2 -1
  100. package/examples/templates/showcase/vue-remote/src/pages/OrderDetail.vue +2 -1
  101. package/examples/templates/showcase/vue-remote/src/pages/OrderList.vue +2 -1
  102. package/examples/templates/vue-host-react-remote/README.md +24 -0
  103. package/examples/templates/vue-host-react-remote/package.json +2 -1
  104. package/examples/templates/vue-host-react-remote/pnpm-lock.yaml +7 -7
  105. package/examples/templates/vue-host-react-remote/pnpm-workspace.yaml +1 -1
  106. package/examples/templates/vue-host-react-remote/react-remote/README.md +17 -17
  107. package/examples/templates/vue-host-react-remote/react-remote/fulgurjs.config.ts +2 -2
  108. package/examples/templates/vue-host-react-remote/react-remote/package.json +1 -1
  109. package/examples/templates/vue-host-react-remote/react-remote/src/{bridge.tsx → application.tsx} +13 -24
  110. package/examples/templates/vue-host-react-remote/react-remote/src/main.tsx +2 -7
  111. package/examples/templates/vue-host-react-remote/scripts/prod.mjs +101 -0
  112. package/examples/templates/vue-host-react-remote/vue-host/package.json +1 -1
  113. package/examples/templates/vue-host-react-remote/vue-host/src/application.ts +5 -0
  114. package/examples/templates/vue-host-react-remote/vue-host/src/main.ts +2 -4
  115. package/examples/templates/vue-vue/README.md +25 -1
  116. package/examples/templates/vue-vue/host/package.json +1 -1
  117. package/examples/templates/vue-vue/host/src/application.ts +54 -0
  118. package/examples/templates/vue-vue/host/src/main.ts +3 -50
  119. package/examples/templates/vue-vue/package.json +2 -1
  120. package/examples/templates/vue-vue/pnpm-lock.yaml +7 -7
  121. package/examples/templates/vue-vue/pnpm-workspace.yaml +1 -1
  122. package/examples/templates/vue-vue/remote/package.json +1 -1
  123. package/examples/templates/vue-vue/remote/src/application.ts +6 -0
  124. package/examples/templates/vue-vue/remote/src/main.ts +3 -5
  125. package/examples/templates/vue-vue/scripts/prod.mjs +101 -0
  126. package/package.json +14 -9
  127. package/examples/templates/react-host-vue-remote/react-host/src/fulgurjs/types/bridge-vue-remote/metadata.json +0 -15
  128. package/examples/templates/react-host-vue-remote/react-host/src/fulgurjs/types/bridge-vue-remote/modules.d.ts +0 -14
  129. package/examples/templates/react-host-vue-remote/react-host/src/fulgurjs/types/bridge-vue-remote/registry.d.ts +0 -10
  130. package/examples/templates/react-host-vue-remote/vue-remote/src/bridge.ts +0 -57
  131. package/examples/templates/showcase/react-host/src/fulgurjs/types/vue-remote/metadata.json +0 -16
  132. package/examples/templates/showcase/react-host/src/fulgurjs/types/vue-remote/modules.d.ts +0 -71
  133. package/examples/templates/showcase/react-host/src/fulgurjs/types/vue-remote/registry.d.ts +0 -10
  134. package/examples/templates/showcase/vue-host/src/fulgurjs/types/react-remote/metadata.json +0 -16
  135. package/examples/templates/showcase/vue-host/src/fulgurjs/types/react-remote/modules.d.ts +0 -79
  136. package/examples/templates/showcase/vue-host/src/fulgurjs/types/react-remote/registry.d.ts +0 -10
  137. package/examples/templates/vue-host-react-remote/vue-host/src/fulgurjs/types/bridge-react-remote/metadata.json +0 -16
  138. package/examples/templates/vue-host-react-remote/vue-host/src/fulgurjs/types/bridge-react-remote/modules.d.ts +0 -10
  139. package/examples/templates/vue-host-react-remote/vue-host/src/fulgurjs/types/bridge-react-remote/registry.d.ts +0 -10
@@ -0,0 +1,28 @@
1
+ import { createApp } from 'vue'
2
+ import { createRouter, createWebHistory } from 'vue-router'
3
+ import { defineApplication } from '@fulgurjs/federation/vue'
4
+ import App from './App.vue'
5
+ import HomePage from './pages/HomePage.vue'
6
+ import AboutPage from './pages/AboutPage.vue'
7
+ import BridgeReactPage from './pages/BridgeReactPage.vue'
8
+ import { initBridgeRouting } from './routing'
9
+ import { installGuard } from './guard'
10
+ import { installPopStateLogger } from './demo-log'
11
+
12
+ export default defineApplication((_props, { signal }) => {
13
+ const router = createRouter({
14
+ history: createWebHistory(import.meta.env.BASE_URL),
15
+ routes: [
16
+ { path: '/', component: HomePage },
17
+ { path: '/about', component: AboutPage },
18
+ // catch-all:子应用挂载在 /br-react 前缀下,内部导航全部命中同一条路由记录
19
+ { path: '/br-react/:pathMatch(.*)*', component: BridgeReactPage },
20
+ ],
21
+ })
22
+
23
+ initBridgeRouting(router)
24
+ installGuard(router)
25
+ installPopStateLogger(signal)
26
+
27
+ return { app: createApp(App), router }
28
+ })
@@ -37,13 +37,10 @@ export function handleChildEvent(event: DemoChildEvent): void {
37
37
  logNav(event.source, `${event.action} ${event.detail}`)
38
38
  }
39
39
 
40
- let popInstalled = false
41
-
42
- /** 浏览器前进后退(POP)在 main.ts 安装一次;push/replace 由各自来源显式标注 */
43
- export function installPopStateLogger(): void {
44
- if (popInstalled) return
45
- popInstalled = true
40
+ /** POP 观测属于本应用实例;卸载后由 signal 移除,不遗留窗口监听。 */
41
+ export function installPopStateLogger(signal: AbortSignal): void {
42
+ if (signal.aborted) return
46
43
  window.addEventListener('popstate', () => {
47
44
  logNav('浏览器前进后退', window.location.pathname + window.location.search)
48
- })
45
+ }, { signal })
49
46
  }
@@ -1,30 +1,2 @@
1
- /**
2
- * examples/templates/showcase/vue-host/src/main.ts — 宿主入口。
3
- * 宿主 Router 是浏览器历史唯一写入方;catch-all 路由(/br-react/* 单条记录渲染同一组件)
4
- * 保证子应用内部导航不重挂宿主组件。守卫与 POP 日志在此一次性安装。
5
- */
6
- import { createApp } from 'vue'
7
- import { createRouter, createWebHistory } from 'vue-router'
8
- import App from './App.vue'
9
- import HomePage from './pages/HomePage.vue'
10
- import AboutPage from './pages/AboutPage.vue'
11
- import BridgeReactPage from './pages/BridgeReactPage.vue'
12
- import { initBridgeRouting } from './routing'
13
- import { installGuard } from './guard'
14
- import { installPopStateLogger } from './demo-log'
15
-
16
- const router = createRouter({
17
- history: createWebHistory(),
18
- routes: [
19
- { path: '/', component: HomePage },
20
- { path: '/about', component: AboutPage },
21
- // catch-all:子应用挂载在 /br-react 前缀下,内部导航全部命中同一条路由记录
22
- { path: '/br-react/:pathMatch(.*)*', component: BridgeReactPage },
23
- ],
24
- })
25
-
26
- initBridgeRouting(router)
27
- installGuard(router)
28
- installPopStateLogger()
29
-
30
- createApp(App).use(router).mount('#app')
1
+ import application from './application'
2
+ void application.start('#app').catch(console.error)
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * examples/templates/showcase/vue-host/src/routing.ts — 桥接宿主导航端口(模块级单例)。
3
- * main.ts 组装宿主 router 后初始化一次:createVueBridgeNavigation(router)——
3
+ * application.ts 组装宿主 router 后初始化一次:createVueBridgeNavigation(router)——
4
4
  * Vue Router fullPath 已剥离 history base,逻辑路径无需再处理部署前缀;
5
5
  * 端口引用保持稳定 → routing 键不变,宿主不重挂、不重复订阅。
6
6
  */
@@ -16,6 +16,6 @@ export function initBridgeRouting(router: Router): void {
16
16
  }
17
17
 
18
18
  export function getBridgeRouting(): BridgeHostRouting {
19
- if (!routing) throw new Error('桥接路由端口未初始化:请先在 main.ts 调用 initBridgeRouting(router)')
19
+ if (!routing) throw new Error('桥接路由端口未初始化:请先在 application.ts 调用 initBridgeRouting(router)')
20
20
  return routing
21
21
  }
@@ -9,7 +9,7 @@ export default {
9
9
  name: 'vue-remote',
10
10
  filename: 'fulgurjs-remoteEntry.js',
11
11
  exposes: {
12
- './bridge': './src/bridge.ts',
12
+ './bridge': './src/application.ts',
13
13
  },
14
14
  shared: {
15
15
  vue: { singleton: true },
@@ -11,7 +11,7 @@
11
11
  "types": "fulgurjs types"
12
12
  },
13
13
  "dependencies": {
14
- "@fulgurjs/federation": "6.8.5",
14
+ "@fulgurjs/federation": "6.9.0",
15
15
  "vue": "^3.5.13",
16
16
  "vue-router": "^4.5.0"
17
17
  },
@@ -7,7 +7,8 @@
7
7
  import { getCurrentInstance } from 'vue'
8
8
  import { hasBridgeMount } from '@fulgurjs/federation/vue'
9
9
  import { RouterView, useRouter } from 'vue-router'
10
- import { getMountCount, reportNav } from './child-bus'
10
+ import { useChildReporter } from './child-bus'
11
+ const { getMountCount, reportNav } = useChildReporter()
11
12
 
12
13
  // 查询当前 app,而不是页面是否存在其他桥接实例。
13
14
  const bridged = hasBridgeMount(getCurrentInstance()?.appContext.app)
@@ -39,7 +40,7 @@ const handleGoForward = (): void => {
39
40
  <section class="demo-child">
40
41
  <p data-demo-bridge-mode>当前应用被桥接:{{ String(bridged) }}</p>
41
42
  <p class="demo-child-title">
42
- <strong>Vue 子应用</strong>(受控 memory 路由)· 本会话挂载次数:{{ getMountCount() }}
43
+ <strong>Vue 子应用</strong>({{ bridged ? '受控 memory' : '独立 web' }} 路由)· 本会话挂载次数:{{ getMountCount() }}
43
44
  </p>
44
45
  <div class="demo-row">
45
46
  <button @click="handlePushDemo">子应用 push /orders?q=演示&amp;page=2</button>
@@ -1,17 +1,13 @@
1
- /**
2
- * examples/templates/showcase/vue-remote/src/bridge.ts — Vue 子应用桥接契约(exposes './bridge')。
3
- * defineBridgeApp(factory, { routing: true }) 声明路由协议(缺失时宿主启用同步即 MFU-031 占位)。
4
- * 返回 { app, router },插件等待初始位置、安装路由、挂载并在卸载时释放连接。
5
- */
1
+ // 独立与桥接装配唯一入口;返回未安装的 app/router,交给插件等待与挂载。
6
2
  import { createApp } from 'vue'
7
- import { createMemoryHistory, createRouter, type RouteRecordRaw } from 'vue-router'
8
- import { defineBridgeApp } from '@fulgurjs/federation/vue'
3
+ import { createMemoryHistory, createWebHistory, createRouter, type RouteRecordRaw } from 'vue-router'
4
+ import { defineApplication } from '@fulgurjs/federation/vue'
9
5
  import ChildLayout from './ChildLayout.vue'
10
6
  import OrderList from './pages/OrderList.vue'
11
7
  import OrderDetail from './pages/OrderDetail.vue'
12
8
  import Settings from './pages/Settings.vue'
13
9
  import Locked from './pages/Locked.vue'
14
- import { bindReporter, reportNav } from './child-bus'
10
+ import { createChildReporter, childReporterKey, type ChildProps } from './child-bus'
15
11
 
16
12
  const routes: RouteRecordRaw[] = [
17
13
  // 根路径以 replace 规范化到 /orders(不产生额外历史条目)
@@ -22,19 +18,20 @@ const routes: RouteRecordRaw[] = [
22
18
  { path: '/locked', component: Locked },
23
19
  ]
24
20
 
25
- export default defineBridgeApp((props, ctx) => {
26
- bindReporter(props)
21
+ export default defineApplication<ChildProps>((props, ctx) => {
22
+ const reporter = createChildReporter(props, ctx.signal)
27
23
  // 初始位置先读快照(规范化 replace 后对比上报)
28
24
  const init = ctx?.routing?.getLocation()
29
25
  const initPath = init ? init.pathname + init.search + init.hash : ''
30
- const router = createRouter({ history: createMemoryHistory(), routes })
31
- const app = createApp(ChildLayout, props)
26
+ const router = createRouter({ history: ctx.mode === 'bridge' ? createMemoryHistory() : createWebHistory(import.meta.env.BASE_URL), routes })
27
+ const app = createApp(ChildLayout)
28
+ app.provide(childReporterKey, reporter)
32
29
  // afterEach 记录初始导航结果;路由安装与连接清理由插件负责。
33
30
  let reported = false
34
31
  router.afterEach((to, _from, failure) => {
35
32
  if (reported || failure) return
36
33
  reported = true
37
- reportNav(
34
+ reporter.reportNav(
38
35
  '子应用初始化',
39
36
  'init',
40
37
  to.fullPath !== initPath
@@ -1,32 +1,32 @@
1
- /**
2
- * examples/templates/showcase/vue-remote/src/child-bus.ts — 子应用 → 宿主观测台上报总线。
3
- * 宿主经 appProps 传入稳定回调 onChildEvent;本模块持有该引用并维护挂载计数。
4
- * 单页单实例假设:同一宿主页同时只挂一个本子应用实例(路由同步前缀互斥的常规形态)。
5
- */
6
- export type DemoChildNavAction = 'push' | 'replace' | 'go' | 'init'
1
+ /** 应用实例自己的观测回调,通过原生 provide/Context 传给实际消费树。 */
2
+ import { inject, type InjectionKey } from 'vue'
7
3
 
4
+ export type DemoChildNavAction = 'push' | 'replace' | 'go' | 'init'
8
5
  export type DemoChildEvent =
9
6
  | { type: 'mounted'; mountCount: number }
10
7
  | { type: 'nav'; source: string; action: DemoChildNavAction; detail: string }
11
-
12
8
  export type DemoChildReporter = (event: DemoChildEvent) => void
13
-
14
- const bus: { report: DemoChildReporter | undefined } = { report: undefined }
15
- let mountCount = 0
16
-
17
- /** 桥接工厂内调用:从 props 快照中取出宿主回调,并上报本次挂载计数 */
18
- export function bindReporter(props: Record<string, unknown> | undefined): void {
19
- const candidate = (props as { onChildEvent?: DemoChildReporter } | undefined)?.onChildEvent
20
- bus.report = typeof candidate === 'function' ? candidate : undefined
21
- mountCount += 1
22
- bus.report?.({ type: 'mounted', mountCount })
9
+ export interface ChildReporter {
10
+ reportNav(source: string, action: DemoChildNavAction, detail: string): void
11
+ getMountCount(): number
23
12
  }
24
-
25
- /** 导航来源上报(子应用 Link / 子应用 push·replace / 子应用 go / 子应用初始化) */
26
- export function reportNav(source: string, action: DemoChildNavAction, detail: string): void {
27
- bus.report?.({ type: 'nav', source, action, detail })
13
+ export interface ChildProps { onChildEvent?: DemoChildReporter }
14
+ // 仅观测编号跨挂载累加;回调和所属实例不放在模块全局。
15
+ let nextMount = 0
16
+ export function createChildReporter(props: ChildProps, signal: AbortSignal): ChildReporter {
17
+ const mountCount = ++nextMount
18
+ if (!signal.aborted) props.onChildEvent?.({ type: 'mounted', mountCount })
19
+ return {
20
+ getMountCount: () => mountCount,
21
+ reportNav(source, action, detail) {
22
+ if (!signal.aborted) props.onChildEvent?.({ type: 'nav', source, action, detail })
23
+ },
24
+ }
28
25
  }
29
26
 
30
- export function getMountCount(): number {
31
- return mountCount
27
+ export const childReporterKey: InjectionKey<ChildReporter> = Symbol('child-reporter')
28
+ export function useChildReporter(): ChildReporter {
29
+ const reporter = inject(childReporterKey)
30
+ if (!reporter) throw new Error('子应用观测台未装配;从 application 工厂启动本应用。')
31
+ return reporter
32
32
  }
@@ -1,16 +1,2 @@
1
- /**
2
- * examples/templates/showcase/vue-remote/src/main.ts — 独立运行入口(仅 dev 占位)。
3
- * 子应用真实能力经 exposes './bridge' 被宿主加载;直开本页仅作 dev server 健康检查。
4
- */
5
- import { createApp, h } from 'vue'
6
-
7
- createApp({
8
- render: () =>
9
- h('div', { style: "font-family: 'PingFang SC', 'Microsoft YaHei', sans-serif; padding: 24px" }, [
10
- h('h1', null, 'vue-remote(联邦子应用,默认端口 5335,改端口见 README「改端口」清单)'),
11
- h('p', null, '本应用通过 expose ./bridge(defineBridgeApp + routing 协议)被宿主加载。'),
12
- h('p', null, [
13
- h('a', { href: 'http://localhost:5336/br-vue/orders' }, '打开 React 宿主桥接页(默认 5336)'),
14
- ]),
15
- ]),
16
- }).mount('#app')
1
+ import application from './application'
2
+ void application.start('#app').catch(console.error)
@@ -4,7 +4,8 @@
4
4
  * 前往本页的导航会被宿主守卫(Vue:异步 beforeEach;React:useBlocker)拦截,等待「继续/取消」。
5
5
  */
6
6
  import { useRouter } from 'vue-router'
7
- import { reportNav } from '../child-bus'
7
+ import { useChildReporter } from '../child-bus'
8
+ const { reportNav } = useChildReporter()
8
9
 
9
10
  const router = useRouter()
10
11
 
@@ -5,7 +5,8 @@
5
5
  */
6
6
  import { computed } from 'vue'
7
7
  import { useRoute, useRouter } from 'vue-router'
8
- import { reportNav } from '../child-bus'
8
+ import { useChildReporter } from '../child-bus'
9
+ const { reportNav } = useChildReporter()
9
10
 
10
11
  const route = useRoute()
11
12
  const router = useRouter()
@@ -6,7 +6,8 @@
6
6
  */
7
7
  import { computed, ref } from 'vue'
8
8
  import { useRoute, useRouter } from 'vue-router'
9
- import { reportNav } from '../child-bus'
9
+ import { useChildReporter } from '../child-bus'
10
+ const { reportNav } = useChildReporter()
10
11
 
11
12
  interface OrderItem {
12
13
  id: number
@@ -1,5 +1,8 @@
1
1
  # vue-host-react-remote:完整子应用桥接模板
2
2
 
3
+ > 本目录是 6.9.0 源码候选:已改用 defineApplication,尚未测试和发布。源码依赖已锁定 6.9.0;正式发布前不要拿旧 registry 包运行这份代码。验收先使用本次候选 tarball,发布后再按下列冻结安装命令验证正式包。
4
+
5
+
3
6
  `vue-host/` 是宿主,`react-remote/` 是子应用。复制整个模板目录,在根目录运行:
4
7
 
5
8
  ```bash
@@ -22,3 +25,24 @@ pnpm dev
22
25
  - 改react-remote(默认 5303):① `react-remote/package.json` 的 `dev` 与 `preview` 两个脚本的 `--port 5303`;② `vue-host/fulgurjs.config.ts` 里 `remotes['bridge-react-remote'].dev` 的 `http://localhost:5303`;③ 根 `scripts/dev.config.json` 里 react-remote 的 `port`(**必改**:启动器预检/探活都读它);④ 本 README 顶部端口表。
23
26
  - 改vue-host(默认 5314):① `vue-host/package.json` 的 `dev`/`preview` `--port 5314`;② `scripts/dev.config.json`;③ 本 README 端口表。
24
27
  - 生产部署地址(`prod`,如 `/react-remote`)是站点路径,与 dev 端口无关,改端口不要动它。改名(容器名)不建议:还需同步 spec 前缀与页面表。
28
+
29
+ ## 一键运行生产产物
30
+
31
+ ```bash
32
+ pnpm build
33
+ pnpm prod
34
+ ```
35
+
36
+ `prod` 只服务本次 dist,不启动远程开发服务器。它复用 scripts/dev.config.json 的宿主端口,从实际构建入口推导 base,并把远程静态产物挂在同源子路径。无需为本地复现手写 Nginx;部署真实服务器时仍按部署指南配置。多宿主模板分别启动各宿主地址,不把两个宿主的根资源混在一起。先停止 dev,端口占用会失败并停止本次已起服务;不会关闭已有占用进程。Ctrl+C 关闭本次生产服务。
37
+
38
+ ## 插件代码阅读地图
39
+
40
+ | 文件 | 职责 |
41
+ |---|---|
42
+ | `react-remote/src/application.tsx` | 本应用唯一装配;main 只负责调用 start |
43
+ | `vue-host/src/application.ts` | 本应用唯一装配;main 只负责调用 start |
44
+ | `react-remote/fulgurjs.config.ts` | 本应用的远程地址、exposes、实际共享依赖 |
45
+ | `vue-host/fulgurjs.config.ts` | 本应用的远程地址、exposes、实际共享依赖 |
46
+ | `scripts/dev.mjs` / `scripts/prod.mjs` | 统一开发/生产启动器;业务接入不复制它们到应用源码 |
47
+
48
+ `application` 是新增的插件装配文件,`main` 是已有入口接线;页面组件、业务路由、权限和数据不是每个项目都必写的联邦配置。跨框架基础组合不逐页登记子应用菜单;逐页远程页面模板的页面表仅服务它所展示的逐页场景。`src/fulgurjs/types/` 是插件生成目录,按远程实际版本同步,不维护人工伪造的声明或旧缓存。
@@ -6,6 +6,7 @@
6
6
  "dev:remote": "pnpm --dir react-remote dev",
7
7
  "dev:host": "pnpm --dir vue-host dev",
8
8
  "dev": "node scripts/dev.mjs",
9
- "build": "pnpm --dir react-remote build && pnpm --dir vue-host build"
9
+ "build": "pnpm --dir react-remote build && pnpm --dir vue-host build",
10
+ "prod": "node scripts/prod.mjs"
10
11
  }
11
12
  }
@@ -11,8 +11,8 @@ importers:
11
11
  react-remote:
12
12
  dependencies:
13
13
  '@fulgurjs/federation':
14
- specifier: 6.8.5
15
- version: 6.8.5(react-dom@19.3.0(react@19.3.0))(react-router-dom@7.18.4(react-dom@19.3.0(react@19.3.0))(react@19.3.0))(react@19.3.0)(vite@6.4.4)(vue@3.5.43(typescript@5.9.3))
14
+ specifier: 6.9.0
15
+ version: 6.9.0(react-dom@19.3.0(react@19.3.0))(react-router-dom@7.18.4(react-dom@19.3.0(react@19.3.0))(react@19.3.0))(react@19.3.0)(vite@6.4.4)(vue@3.5.43(typescript@5.9.3))
16
16
  react:
17
17
  specifier: ^19.1.0
18
18
  version: 19.3.0
@@ -42,8 +42,8 @@ importers:
42
42
  vue-host:
43
43
  dependencies:
44
44
  '@fulgurjs/federation':
45
- specifier: 6.8.5
46
- version: 6.8.5(react-dom@19.3.0(react@19.3.0))(react-router-dom@7.18.4(react-dom@19.3.0(react@19.3.0))(react@19.3.0))(react@19.3.0)(vite@6.4.4)(vue@3.5.43(typescript@5.9.3))
45
+ specifier: 6.9.0
46
+ version: 6.9.0(react-dom@19.3.0(react@19.3.0))(react-router-dom@7.18.4(react-dom@19.3.0(react@19.3.0))(react@19.3.0))(react@19.3.0)(vite@6.4.4)(vue@3.5.43(typescript@5.9.3))
47
47
  react:
48
48
  specifier: ^19.1.0
49
49
  version: 19.3.0
@@ -470,8 +470,8 @@ packages:
470
470
  cpu: [x64]
471
471
  os: [win32]
472
472
 
473
- '@fulgurjs/federation@6.8.5':
474
- resolution: {integrity: sha512-RsaN4n2ZgGBtI9zVQxDclS3QxYVKAZiCGipXR3umreAg651tIYCmtqkVjqPELSCPW9tg/rYQvzzs/SOV6ZiQfg==}
473
+ '@fulgurjs/federation@6.9.0':
474
+ resolution: {tarball: https://registry.npmjs.org/@fulgurjs/federation/-/federation-6.9.0.tgz}
475
475
  engines: {node: '>=18'}
476
476
  hasBin: true
477
477
  peerDependencies:
@@ -1284,7 +1284,7 @@ snapshots:
1284
1284
  '@esbuild/win32-x64@0.27.7':
1285
1285
  optional: true
1286
1286
 
1287
- '@fulgurjs/federation@6.8.5(react-dom@19.3.0(react@19.3.0))(react-router-dom@7.18.4(react-dom@19.3.0(react@19.3.0))(react@19.3.0))(react@19.3.0)(vite@6.4.4)(vue@3.5.43(typescript@5.9.3))':
1287
+ '@fulgurjs/federation@6.9.0(react-dom@19.3.0(react@19.3.0))(react-router-dom@7.18.4(react-dom@19.3.0(react@19.3.0))(react@19.3.0))(react@19.3.0)(vite@6.4.4)(vue@3.5.43(typescript@5.9.3))':
1288
1288
  dependencies:
1289
1289
  es-module-lexer: 1.7.0
1290
1290
  esbuild: 0.27.7
@@ -2,7 +2,7 @@ packages:
2
2
  - vue-host
3
3
  - react-remote
4
4
  minimumReleaseAgeExclude:
5
- - '@fulgurjs/federation@6.8.5'
5
+ - '@fulgurjs/federation@6.9.0'
6
6
  # pnpm >=12 构建脚本批准(12 起弃用 onlyBuiltDependencies;pnpm 9-11 忽略本键:
7
7
  # esbuild >=0.16 二进制经 optionalDependencies 平台包分发,postinstall 仅校验,不阻塞安装)
8
8
  allowBuilds:
@@ -1,25 +1,25 @@
1
- # bridge-react-remote — React 桥接子应用示例
1
+ # react-remote — React 子应用
2
2
 
3
- `@fulgurjs/federation` 跨框架桥接的 **React 18/19 子应用**侧示例:以 `defineBridgeApp`(`@fulgurjs/federation/react`)导出 `mount/unmount` 契约,可被 **Vue 宿主**(配合 `examples/templates/vue-host-react-remote/vue-host-react-remote/vue-host`)整站挂载。
3
+ 本模板对应未验收的 6.9.0 源码候选,状态与安装方法见[组合说明](../README.md)。复制整个组合目录,在组合根启动。
4
4
 
5
- ## 运行
5
+ ## 按顺序读源码
6
6
 
7
- 复制整个 `vue-host-react-remote/` 模板,在模板根执行:
7
+ 1. `fulgurjs.config.ts`:`./bridge` 直接 expose `src/application.tsx`,公开模块名称不受文件名称约束。
8
+ 2. `src/application.tsx`:`defineApplication` 唯一装配;独立模式用浏览器路由,桥接模式用本地 memory 路由,两者显示同一套真实页面、计数与 props。
9
+ 3. `src/main.tsx`:只调用 application.start,不再复制初始化或新增转发文件。
10
+ 4. `vue-host/`:宿主的挂载、会话与回调,见[组合说明](../README.md)。
8
11
 
9
- ```bash
10
- pnpm install --frozen-lockfile
11
- pnpm dev # 同时启动宿主和子应用
12
- pnpm build # 构建完整组合
13
- # 单独启动本应用:pnpm --dir react-remote dev
14
- ```
12
+ 应用代码只从 `@fulgurjs/federation/react` 导入插件 API;子应用不因跨框架嵌入而安装另一框架。这个基础组合不启用宿主 URL 同步;需要地址双向同步时使用 showcase 模板。
15
13
 
16
- 端口、复制范围与部署路径见[组合说明](../README.md)。
14
+ 独立启动可以切换首页/关于页,桥接也使用相同页面;卸载与首次挂载由插件管理。Vue 返回未安装的 app/router,React 返回 BrowserRouter/MemoryRouter 内的同一组件树。
17
15
 
18
- ## 关键点
16
+ ## 运行
19
17
 
20
- - `src/bridge.tsx`:`defineBridgeApp((props) => <MemoryRouter>…</MemoryRouter>)`,作为 `./bridge` expose 的默认导出。
21
- - `mount` 的 Promise 在**首次根提交完成后**才 resolve(契约内建提交探针);首次渲染前报错会拒绝挂载并转 MFU-016。
22
- - `react-dom/client` 在实际 mount 时才按需加载;共享子路径 `react-dom/client` 与 `react/jsx-runtime` 由宿主/子应用 shared 配方协商单实例。
23
- - 子应用只安装并共享 `react` + `react-dom`(+ `react-router-dom` 为直接依赖),**不安装 Vue**。
18
+ ```bash
19
+ pnpm install --frozen-lockfile
20
+ pnpm dev
21
+ pnpm build
22
+ pnpm prod
23
+ ```
24
24
 
25
- 配套阅读:根目录 README §8.2「跨框架桥接 API — /bridge」。
25
+ 以上正式安装命令须在 6.9.0 发布后执行;候选验收先按组合根的候选说明使用本轮 tarball。
@@ -1,14 +1,14 @@
1
1
  import type { FederationOptions } from '@fulgurjs/federation'
2
2
 
3
3
  /**
4
- * React 子应用联邦配置:`./bridge` expose = defineBridgeApp 契约模块(任务书 §3.3)。
4
+ * React 子应用联邦配置:`./bridge` expose = defineApplication 统一应用契约。
5
5
  * 子应用只安装并共享自己的框架(react + react-dom),不为桥接安装 Vue。
6
6
  */
7
7
  export default {
8
8
  name: 'bridge-react-remote',
9
9
  filename: 'fulgurjs-remoteEntry.js',
10
10
  exposes: {
11
- './bridge': './src/bridge.tsx',
11
+ './bridge': './src/application.tsx',
12
12
  },
13
13
  shared: {
14
14
  react: { singleton: true },
@@ -11,7 +11,7 @@
11
11
  "typecheck": "tsc --noEmit"
12
12
  },
13
13
  "dependencies": {
14
- "@fulgurjs/federation": "6.8.5",
14
+ "@fulgurjs/federation": "6.9.0",
15
15
  "react": "^19.1.0",
16
16
  "react-dom": "^19.1.0",
17
17
  "react-router-dom": "^7.1.0"
@@ -1,12 +1,6 @@
1
- /**
2
- * React 子应用桥接契约(./bridge expose 的默认导出,任务书 §3.3)。
3
- *
4
- * defineBridgeApp 工厂接收 props 快照、返回 ReactElement;
5
- * createRoot/首次提交探测/unmount 由契约实现负责(react-dom/client 在实际 mount 时按需加载)。
6
- */
7
1
  import { useEffect, useState } from 'react'
8
- import { MemoryRouter, Route, Routes, useLocation, useNavigate } from 'react-router-dom'
9
- import { defineBridgeApp } from '@fulgurjs/federation/react'
2
+ import { BrowserRouter, MemoryRouter, Route, Routes, useLocation, useNavigate } from 'react-router-dom'
3
+ import { defineApplication } from '@fulgurjs/federation/react'
10
4
 
11
5
  /** 挂载即回调(宿主验证函数引用跨 root 传递) */
12
6
  function OnReady({ onReady }: { onReady?: () => void }) {
@@ -27,14 +21,16 @@ function Counter() {
27
21
  )
28
22
  }
29
23
 
30
- function Shell(props: Record<string, unknown>) {
24
+ export interface BridgeReactProps { label?: string; onReady?: () => void }
25
+
26
+ function Shell(props: BridgeReactProps) {
31
27
  const location = useLocation()
32
28
  const navigate = useNavigate()
33
29
  return (
34
30
  <div style={{ border: '1px solid #61dafb', borderRadius: 8, padding: 12, fontFamily: 'sans-serif' }}>
35
31
  <p style={{ margin: '0 0 6px', fontWeight: 600, color: '#0b7285' }}>React 子应用</p>
36
32
  <p data-testid="demo-react-props" style={{ margin: '0 0 6px' }}>
37
- {`appProps.label = ${(props as any).label || '(未传)'}`}
33
+ {`appProps.label = ${props.label || '(未传)'}`}
38
34
  </p>
39
35
  <p data-testid="demo-react-route" style={{ margin: '0 0 8px' }}>{`memory 路由:${location.pathname}`}</p>
40
36
  <nav style={{ marginBottom: 8 }}>
@@ -50,17 +46,10 @@ function Shell(props: Record<string, unknown>) {
50
46
  )
51
47
  }
52
48
 
53
- export function App() {
54
- return (
55
- <MemoryRouter>
56
- <Shell />
57
- </MemoryRouter>
58
- )
59
- }
60
-
61
- export default defineBridgeApp((props) => (
62
- <MemoryRouter>
63
- <OnReady onReady={(props as any).onReady} />
64
- <Shell {...props} />
65
- </MemoryRouter>
66
- ))
49
+ // 独立入口与桥接共享同一套页面、状态和 onReady。
50
+ export default defineApplication<BridgeReactProps>((props, { mode }) => {
51
+ const content = <><OnReady onReady={props.onReady} /><Shell {...props} /></>
52
+ return mode === 'bridge'
53
+ ? <MemoryRouter>{content}</MemoryRouter>
54
+ : <BrowserRouter basename={import.meta.env.BASE_URL}>{content}</BrowserRouter>
55
+ })
@@ -1,7 +1,2 @@
1
- import { createElement } from 'react'
2
- import { createRoot } from 'react-dom/client'
3
- import { App } from './bridge'
4
-
5
- // 独立运行入口:单独开发/调试子应用自身时使用。
6
- // 被桥接宿主消费时走 fulgurjs-remoteEntry.js 容器入口与 ./bridge 契约,与本文件无关。
7
- createRoot(document.getElementById('root')!).render(createElement(App))
1
+ import application from './application'
2
+ void application.start('#root', { label: '独立 React 子应用' }).catch(console.error)