@fulgurjs/federation 2.0.1 → 2.0.3

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 CHANGED
@@ -1,5 +1,65 @@
1
1
  # Changelog
2
2
 
3
+ ## 2.0.3(2026-09-23)
4
+
5
+ ### 修复(production remote CSS manifest / preload)
6
+
7
+ - **修复 expose manifest 漏报 CSS**:Vite 可将 expose 导入的全局 CSS 归属到其静态依赖 chunk;此前插件只读取 expose facade 自身的 `viteMetadata.importedCss`,导致样式不进入 `fulgurjs-manifest.json`。现在在 `generateBundle` post 阶段递归收集 expose 静态依赖图中的 CSS,再写入对应 expose 条目。
8
+ - **修复根相对 remote 地址**:配置 `prod: '/lowcode'` 时也能生成 `/lowcode/fulgurjs-manifest.json`;保留绝对地址与协议相对地址的 origin/path 语义。
9
+ - **运行时按 expose 加载样式**:`loadRemote('remote/Expose')` 在 manifest 可用时预载该 expose 的 JS chunk 与 CSS,并等待 stylesheet load/error 后再返回模块;仅传 remote 名时保留预载全部 exposes 的行为。CSS 失败报告 `MFU-007`,不阻断 JS 模块加载。
10
+ - **补齐 build 后置转换**:build 阶段允许处理 pre 阶段标记过、但随后由 auto-import 等插件注入新 import 的模块;依赖 `transformModule` 幂等,serve 路径维持原有重复处理守卫。
11
+ - **回归验证**:覆盖静态依赖 chunk 持有 CSS、根相对 manifest URL、请求 expose 的 CSS 预载与等待行为;8662 实际运行态认证弹窗验收 computed `z-index: 5000`。
12
+
13
+ ## 2.0.2(2026-09-22)
14
+
15
+ ### 修复(D6:双向宿主 devSharedSelf 开启后 prod 构建产物 chunk 循环崩溃)
16
+
17
+ - **缺陷**:双向联邦宿主(既 expose 又消费 remote)按文档口径设置 `devSharedSelf: true` 后,
18
+ `vite build` 成功但 prod 运行时崩溃——`SyntaxError: Unexpected token '<'`(chunk 被 SPA 回退)
19
+ + `TypeError: _e is not a function`(协商函数未初始化)。仅在「宿主 + 用户 manualChunks 强制
20
+ 分组(对象/函数形式)」组合下触发(实测 mes-zc admin:vue-vendor ⇄ antd-vue-vendor 环)。
21
+ - **根因**:`devSharedSelf` 使 node_modules 参与门面化,被 manualChunks 强制分组的包
22
+ (如 vue-vendor 组内 vue-router)内部的 shared 导入被改写为协商门面;门面为静态
23
+ `import` 运行时的 TLA 模块,被 rollup 按消费方归组拖入其他强制组 → 跨组静态环 →
24
+ 门面 TLA 求值顺序错位。
25
+ - **修复 1(门面形态参数化,virtual.ts)**:`genSharedFacade` / `genSharedNsFacade` /
26
+ `genBindingFacade` / `genRemoteBindingFacade` 新增 dynamic 形态——门面对运行时与 shared
27
+ 本体的依赖全部改为 TLA 内 `await import(...)`,命名空间门面以 `{ ...ns }` 复制阻断 rollup
28
+ 透传内联——门面 chunk 对外零静态依赖("汇"形态),与任何 manualChunks 分组正交,不可能成环。
29
+ **dynamic 仅在 devSharedSelf 宿主(build)启用;其余一切场景(纯 remote、dev serve)保持
30
+ 2.0.0 静态形态,产物与行为零变化**(硬约束;纯 remote 若启用动态化会在自动分包下出现
31
+ 「门面 TLA → 动态 import 本体 chunk ← 静态 import 门面」死锁,实测确认)。
32
+ - **修复 2(shared 闭包静态化,transform.ts + index.ts)**:devSharedSelf 宿主(build)下,
33
+ provide 键本体闭包内的模块(如 vue-router 包、vue-demi 转发层——经 shared 本体文件解析
34
+ 传递依赖)对 shared 键的导入**不做门面化**(同一 provide 闭包天然同实例)——斩断
35
+ 「fallback 动态 import 本体 chunk ← 本体消费方静态 import 门面」的 TLA 混合环(实机死锁:
36
+ 页面停在骨架屏、零报错)。别名转发层的 `export * from <key>` 因此保持静态、不再触发
37
+ ESM 门面化硬报错。纯 remote 不启用,行为零变化(硬约束)。
38
+ - **修复 3(manualChunks 包装注入,index.ts)**:devSharedSelf 宿主 + 用户配置了
39
+ manualChunks 时,插件包装注入归组函数——运行时隔离进 `fulgurjs-runtime` 组、协商门面按
40
+ shareKey 隔离进 `fulgurjs-shared-<key>` 组、远程绑定门面进 `fulgurjs-remote-facades-*` 组。
41
+ 对象形式的 specifier 解析延迟到 buildStart(走完整解析管线含 alias),解析失败丢组并告警。
42
+ - **修复 4(post 阶段 auto-import 兜底,index.ts)**:build 下 post.transform 不再跳过非
43
+ `.vue` 文件——unplugin-auto-import 等后置插件注入的 `import { ref } from 'vue'` 发生在
44
+ pre.transform 之后,此前会绕过门面化、静态绑定本地 vue 副本,与协商实例形成**双响应性
45
+ 系统**(实测:同一组件内 A ref 的赋值不触发渲染、B ref 的赋值正常;jsdelivr 级表现即
46
+ 「弹窗 model 置 true 却不渲染」)。pre 已改写过的文件由 `isPluginProcessedModule` 守卫
47
+ 拦下,不会双重改写。
48
+ - **新增诊断**:`BLD-006`——output 为数组形态时无法自动注入,三段式提示手工加隔离分支。
49
+ - **集成器**:宿主为双向(有 exposes 且有 remotes)时 vite.config 模板产出
50
+ `devSharedSelf: true`(落实 README 口径;须配合本版插件使用)。
51
+ - **测试**:+10(门面 dynamic/static 双形态断言 ×6、真实 vite build 产物形态用例 ×1——
52
+ 覆盖「宿主 + devSharedSelf + manualChunks 对象形式」这条此前零覆盖的路径,断言产物无环、
53
+ 门面隔离、"汇"形态、node_modules 门面化指向隔离 chunk;post 兜底源码契约 ×3)。
54
+
55
+ ### 已知边界
56
+
57
+ - devSharedSelf 宿主的协商门面 chunk 集中在插件专属组:与「门面分散在各业务 chunk」的
58
+ 旧形态相比,首屏会多下载所属 shareKey 的门面 chunk(未压缩量级 = 门面行数,gzip 后显著
59
+ 缩小);这是换取「与 manualChunks 共存」的结构性代价。
60
+ - 入口文件(index.html 直引的模块)内的 remote 导入在 build 下不参与改写(入口只内联 init
61
+ 即短路返回,既有边界):remote 导入请放在非入口模块。
62
+
3
63
  ## 2.0.1(2026-09-22)
4
64
 
5
65
  ### 变更(文档与包面,零运行时变化)
package/README.md CHANGED
@@ -120,9 +120,13 @@ const Panel = await loadRemote('shop/Panel', {
120
120
  })
121
121
  ```
122
122
 
123
- > **在任何文件都可以直接这样导入**——包括 exposes 目标文件(远程页面)。远程页面里的该导入会被
123
+ > **普通源码文件都可以直接这样导入**——包括 exposes 目标文件(远程页面)。远程页面里的该导入会被
124
124
  > 插件自动改写为惰性单例委托:求值期零副作用、调用期转发页面级运行时单例,无需关心宿主/远程的区别。
125
125
 
126
+ > **构建入口文件是边界**:Vite 的 HTML module entry 在 build 时由插件优先内联 init 并直接返回,入口文件自身的 remote import 不会进入改写管线。把 `import('remote-a/Page')` 放在入口导入的普通模块中;不要在 `main.ts` / `main.js` 里直接写 remote import。该边界是有意保留的,不代表入口文件中的语法也会被改写。
127
+
128
+ `loadRemote('remote-a/Page')` 在 remote 配置提供 manifest 时,会先按 expose 预载对应 CSS,再解析返回模块;CSS 请求失败会报告 `MFU-007`,但不会阻断 JS 模块加载。expose 若依赖全局 CSS,需从该 expose 的依赖图中导入,确保资源进入 manifest。
129
+
126
130
  > 以上只是最小面。**全部选项(remotes 四形态/shared 九个开关/dts/runtimePlugins…)、运行时 API、CLI、错误码见下方 [API 参考](#api-参考)。**
127
131
 
128
132
  **没有别的步骤了。** dev 下 remote 跑它自己的 `vite dev`(容器入口 `/@fulgurjs-entry.js` 由插件中间件直出);build 下 expose 自动拆独立 chunk、shared 自动剥离——同一份配置两端通用。
@@ -174,7 +178,7 @@ import { federation, type FederationOptions } from '@fulgurjs/federation'
174
178
  | `manifest` | `boolean` | `true` | prod 构建生成 `fulgurjs-manifest.json`(preloadRemote 依赖它) |
175
179
  | `runtimePlugins` | `string[]` | `[]` | 运行时插件模块路径列表(写法见「运行时插件」) |
176
180
  | `dts` | `boolean \| { dir?: string; mode?: 'source' \| 'shim' }` | `true` | dev 下拉取远程 manifest 生成类型声明——宿主写 `import X from 'remote-a/X'` 获得类型。**产物写入 `src/fulgurjs/types/`(联邦产物集中一个文件夹;无 src 布局回退 `.fulgurjs/types`)**,src 布局项目 tsconfig 零配置即生效;`{ dir }` 自定义位置;`mode: 'source'`(默认)跨工程源码直连(补全/跳转直达远程源码,VSCode 打开生成物可能显示工程外文件诊断);`mode: 'shim'` 宽松占位(不引用源文件,IDE 全程干净,无源码级补全——见 §9.1.5) |
177
- | `devSharedSelf` | `boolean` | 纯远程 `true`;有 `remotes` 的宿主 `false` | dev 下自身源码(含依赖)是否参与 shared 协商改写。**双向联邦**(既 expose 又消费 remote)的宿主/远程需显式 `true`,否则 prod 双 vue 实例 |
181
+ | `devSharedSelf` | `boolean` | 纯远程 `true`;有 `remotes` 的宿主 `false` | dev 下自身源码(含依赖)是否参与 shared 协商改写。**双向联邦**(既 expose 又消费 remote)的宿主/远程**必设 `true`**,否则 prod 双 vue 实例(症状:被消费页面渲染上下文错乱 / `'ce'` / renderSlot null)。2.0.1 起 build 下该路径的协商门面自动隔离进插件专属 chunk(`fulgurjs-runtime` + `fulgurjs-shared-<key>`),与用户 `manualChunks` 强制分组正交、不再产生 chunk 循环依赖(D6 修复,症状曾是 `SyntaxError: Unexpected token '<'` + `TypeError: _e is not a function`) |
178
182
  | `automaticAsyncBoundary` | — | 恒为 `true` | 接受任意值:TLA 自动异步边界,无需手工 bootstrap |
179
183
  | `dataPrefetch` | — | 恒为 `true` | 接受任意值:`preloadRemote` 始终可用 |
180
184
  | `usedExports` / `ignoreUnusedSharedExports` | — | no-op | 接受并忽略(Rollup/Rolldown 原生 tree-shaking 已覆盖) |
@@ -244,7 +248,7 @@ import { loadRemote } from 'virtual:fulgurjs-runtime'
244
248
  |---|---|---|
245
249
  | `loadRemote` | `(spec: string, opts?) => Promise<模块命名空间>` | 加载远程模块。`spec = '远程名/./Expose键'`(`./` 可省);opts 见下 |
246
250
  | `loadShare` | `(name: string, opts?) => Promise<命名空间>` | 共享模块协商(最高版本胜出/已加载优先/singleton 收敛)。opts:`{ requiredVersion?, singleton?, strictVersion?, shareKey?, shareScope?, fallback? }` |
247
- | `preloadRemote` | `(spec: string, opts?: { mode?: 'preload' \| 'prefetch' }) => Promise<void>` | 按 manifest 精确预载该远程全部 expose chunk + CSS(prefetch = 空闲时低优先级) |
251
+ | `preloadRemote` | `(spec: string, opts?: { mode?: 'preload' \| 'prefetch' }) => Promise<void>` | `remote/Expose` 只预载该 expose 的 chunk + CSS;仅传 remote 名则预载全部 exposes。`preload` 等待 CSS load/error,`prefetch` 低优先级并立即返回 |
248
252
  | `getContainer` | `(name: string) => Promise<容器>` | 取远程容器(触发加载 + init),容器协议 `{ name, init, get }` |
249
253
  | `registerRemote` / `registerRemotes` | `(config \| list) => void` | 运行时注册远程(promise remote / 动态地址)。`RemoteInput`:`{ name, entry, shareScope?, timeout?, retries?, fallback?, breaker? }` |
250
254
  | `registerShare` | `(scope, name, version, get, opts?) => void` | 手工注册共享模块(一般由 init 模块自动完成) |
@@ -373,7 +377,7 @@ export default defineRepoConfig({
373
377
  | `fulgurjs init --config <path>` | 校验配置(CFG 三段式报错)+ 输出各应用 `federation()` 粘贴块、NGINX no-cache 站点模板、8 条通用核对清单 |
374
378
  | `fulgurjs doctor --base <URL> --apps <a,b,c>` | 部署体检:remoteEntry/manifest/index.html 的 200/no-cache/JS 形态、CORS、chunk 抽样可达、版本 skew 预演。`--dev` 检查 dev 容器入口;`--json` 输出 JSON(CI 断言);`--chunk-sample N` 控制抽样数(默认 16)。**退出码:有 FAIL 即 1**,可直接做 CI 门禁 |
375
379
 
376
- ### 6. 错误码总表(30 个)
380
+ ### 6. 错误码总表(31 个)
377
381
 
378
382
  | 段 | 码 | 含义 |
379
383
  |---|---|---|
@@ -395,6 +399,7 @@ export default defineRepoConfig({
395
399
  | BLD 构建期 | `BLD-001` | expose 源文件解析失败 |
396
400
  | | `BLD-002` | 构建目标低于 es2022(TLA 需要) |
397
401
  | | `BLD-003` | expose 目标组件含必填 props(文档化核对项) |
402
+ | | `BLD-006` | output 数组形态下无法自动注入协商门面 chunk 隔离(需手工加分支) |
398
403
  | MFU 运行时 | `MFU-001` | 远程容器/模块加载失败(网络/超时/重试耗尽/熔断) |
399
404
  | | `MFU-002` | remoteEntry 自报名与配置名不一致 |
400
405
  | | `MFU-003` | strictVersion 版本不满足 |
@@ -605,7 +610,7 @@ const PREFETCH_REMOTES: string[] = []
605
610
  行为与边界:
606
611
 
607
612
  - 预载失败**不阻断业务**:runtime 按 MFU-007 语义发出 `window` 的 `fulgurjs:error` 事件并 console 警告(诊断面板⑤可查历史);
608
- - 预载仅注入 `<link rel="modulepreload">`,不执行模块——首次打开页面时才真正初始化容器;
613
+ - 预载注入 `<link rel="modulepreload">` 与 `<link rel="stylesheet">`,不执行模块——首次打开页面时才真正初始化容器;`preload` 等待样式 load/error,`prefetch` 低优先级后台加载;
609
614
  - 触发时机:宿主桥每次页面加载同步执行(幂等),实际预取发生在浏览器空闲回调中。
610
615
 
611
616
  #### 9.1.4 联邦诊断面板(免登录页,无配置项)
@@ -697,7 +702,7 @@ const Panel = await loadRemote('shop/Panel', {
697
702
 
698
703
  运行时加载失败同样给排查指引(remote dev server 未启动 / 地址配错 / CORS / NGINX 回退),并携带统一错误码:
699
704
 
700
- 统一错误码体系(CFG/DEV/BLD/MFU 四段共 30 个)——**完整总表见上方 [API 参考 §6](#6-错误码总表30-个)**;报错文案一律「现象 → 根因 → 修法」三段式。
705
+ 统一错误码体系(CFG/DEV/BLD/MFU 四段共 31 个)——**完整总表见上方 [API 参考 §6](#6-错误码总表31-个)**;报错文案一律「现象 → 根因 → 修法」三段式。
701
706
 
702
707
  调试出口:`window.__FULGURJS_SCOPE__`(share 协商实时结果)、`window.__FULGURJS_INFO__`(remote 状态/耗时/错误)。
703
708
 
@@ -1,5 +1,5 @@
1
1
  // src/version.ts
2
- var RUNTIME_VERSION = "2.0.1";
2
+ var RUNTIME_VERSION = "2.0.3";
3
3
 
4
4
  export {
5
5
  RUNTIME_VERSION