常见问题(FAQ)
按主题分组的常见问答。答案保持简明,细节跟随链接到对应章节。
定位与选型
ng-mfe 是什么?
一个基于 Angular 21(Zoneless)的微前端框架,Nx monorepo + Vite + 原生 ES Module 加载,支持 Angular / Vue / React / Web Component / 纯 JS 子应用,并带企业级服务(认证、ACL、缓存、主题、国际化等)。见 什么是微前端 与 架构总览。
为什么不用 iframe?
iframe 天然隔离但代价大:通信只能走 postMessage、URL/路由状态不同步、UI 弹层被裁切、内存占用高。ng-mfe 在同一 Window 内用 Proxy/Snapshot 沙箱 + CSS 隔离达到"够用的隔离",换来原生的事件总线、共享状态与组件复用。对比见 什么是微前端。
为什么不用 Module Federation?
框架选择原生 ES Module 动态 import 作为加载底座,不依赖特定打包器的运行时协议,子应用用任何能产出 ESM 的构建器即可。取舍与理由见决策 不用 Module Federation 与 原生 ES Module。
子应用必须用 Angular 吗?
不必须。Vue、React、Web Component、纯 JS 子应用都有适配器或示例(examples/ 下 5 个子应用各代表一种)。Angular 只是 Portal 与框架自身的实现语言。见 子应用开发。
Vue 子应用怎么接?
使用 defineMfeVueApp 适配器(@ng-mfe/adapters/vue),教程见 Vue 子应用。
React 子应用怎么接?
使用 defineMfeReactApp 适配器(@ng-mfe/adapters/react),教程见 React 子应用。
纯 JavaScript / Web Component 子应用可以吗?
可以。examples/wc-sub 与 examples/custom-sub 就是这两种形态的完整示例,教程见 Web Component 子应用。
必须用 Vite 吗?
框架运行时只要求子应用产出原生 ES Module 入口,理论上任何构建器都可以;仓库内示例与文档以 Vite 为准,未对其他构建器做测试。见 架构:原生 ES Module。
支持子应用独立部署吗?
支持。deploy:build 产物中每个子应用是独立目录(含自己的 index.html 与 assets),可以按目录独立发布;跨域部署时需为子应用 JS 配置 CORS 头。见 生产部署。
机制
Sandbox(沙箱)是什么?
子应用运行时的隔离层:拦截子应用对全局 window 的写入与部分 API(定时器、事件监听、DOM),销毁时还原,避免子应用互相污染宿主。见 架构:沙箱。
ProxySandbox 和 SnapshotSandbox 有什么区别?
ProxySandbox 用 Proxy 代理拦截写入,多实例可并存、隔离更细;SnapshotSandbox 通过"激活前快照、卸载后还原"实现,兼容不支持 Proxy 的环境,但同一时刻只宜有一个激活实例。见 架构:沙箱 与决策 沙箱双模式。
子应用的 CSS 会污染别人吗?
框架提供三种 CSS 隔离模式:prefix(样式前缀)、shadow(Shadow DOM)、scope(作用域属性),在子应用配置中选用。见 架构:沙箱。
内存泄漏怎么防治?
卸载路径统一清理:定时器与事件监听由沙箱 patch 记录并还原,Chart/Map 实例提供 destroy,e2e/memory-leak.spec.ts 做浏览器级验证。业务侧需在卸载回调中释放自己的资源。见 性能实践。
keep-alive(缓存子应用)怎么做?
配置 coexist: true:切走时应用进入 HIDDEN 状态而非销毁,回来时跳过重复加载与引导,即"keep-alive"效果。见 架构:生命周期。
子应用有哪些状态?
AppStatus 状态机:NOT_LOADED → ASSETS_LOADING → ASSETS_LOADED → BOOTSTRAPPING → BOOTSTRAPPED → ACTIVE / HIDDEN,以及 LOAD_ERROR。见 架构:生命周期。
通信
怎么跨应用通信?
三种方式:EventBus(发布/订阅事件)、SharedState(共享状态存储)、RPC(请求/响应式调用)。入门见教程 跨应用通信。
SharedState 和 EventBus 有什么区别?
EventBus 是一次性事件流,适合"发生了什么"(通知、指令);SharedState 是可订阅的状态存储,适合"现在是什么"(当前用户、主题),还支持 protectedKeys 让关键状态仅 Portal 可写。对比见 架构:通信。
RPC 什么时候用?
当你需要"调用方等待返回值"的语义(像函数调用)而不是事件广播时,如子应用向 Portal 请求受保护数据。示例见 RPC 调用。
工程与实践
Cache 的三层是什么?
L1 内存 / L2 会话(SessionStorage)/ L3 持久(LocalStorage),支持 Read-Through 回填、Write-Through 写透、getOrSet 单飞与 LRU 淘汰。见 架构:缓存与缓冲 与教程 缓存。
Auth 并发刷新会发多次请求吗?
不会。refreshToken() 是单飞实现,并发调用只发一次真实请求,其余等待同一结果(有 auth-single-flight.spec 单测佐证)。注意:目前 401 的处理是登出,没有"刷新后重放原请求",后者在路线图中。见 架构:认证。
如何接入地图?
@ng-mfe/ui/map 提供 MapFactory(瓦片缓冲预设、Worker 预热)与 MapLayerRegistry(声明式图层、懒加载、ACL 过滤);maplibre-gl 为可选 peer,按需动态加载。见教程 地图 与 架构:地图。
如何做权限控制?
@ng-mfe/services/acl 的 ACLService:角色(roles)与能力(abilities)两级,支持 can() 判断与变更订阅;MapLayerRegistry 与菜单等均可按 ACL 过滤。见教程 权限 与示例 地图权限。
如何扩展新的框架 Adapter?
参照 packages/adapters 中 angular/vue/react 三个实现:定义生命周期桥接并导出 defineMfeXxxApp,再把子应用入口交由加载器注册。见 架构:扩展。
如何调试子应用?
开发模式各应用独立端口(portal 4200、子应用 4201-4205),可单起 npm run start:angular-sub 等;另有 DevTools 面板(@ng-mfe/devtools)查看应用与状态。故障排查见 故障排查。
文档在哪?能否本地跑?
本站点即仓库 docs-site/,npm run docs:dev 本地开发、docs:build 产出静态站点。API 全量参考见 服务 与 API 索引。
体积有约束吗?
有。.size-limit.json 定义 9 条 gzip 口径上限(core 15KB 等),npm run size:check 在 CI 强制执行。见 性能实践。
怎么参与贡献?
阅读 贡献指南,提交 PR 会经过 CI 六个 job(含测试、类型、体积、Zoneless 守卫)与 E2E。
CI 都检查什么?
六个 job:lint(ESLint + Prettier)、test(覆盖率测试)、build、typecheck(示例类型检查)、size-check(体积预算)、zoneless-guard(禁 zone.js);E2E 工作流另以 deploy 产物跑全部 Playwright 用例。见 工程实践总览。
体积超限了怎么办?
size:check 会失败并指出超限入口。处理顺序:确认没有把重型依赖误加入主入口 → 拆子路径导出 → 用动态 import() 懒加载 → 最后才考虑上调 .size-limit.json(需在 PR 中说明理由)。见 性能实践。
为什么强制禁用 zone.js?
框架基于 Angular 21 Zoneless(Signal 驱动变更检测)设计,引入 zone.js 会破坏这一前提并增加运行时开销;guard:zoneless 脚本在 CI 强制检查(禁 zone.js 依赖与 import、要求 portal/angular-sub 提供 provideZonelessChangeDetection、禁 inject(NgZone))。见决策 Zoneless 与 Signal。
PR 会有部署预览吗?
会。deploy-preview.yml 为每个 PR 构建 dist/deploy 并上传 artifact(保留 7 天),在 PR 评论中给出下载入口,本地 serve 即可预览。见 生产部署。
发布流程是怎样的?
打 v* tag 触发 release 工作流:版本同步 → 构建 → 混淆(medium)→ prepublish 切换发布态 → 产物校验(无 .ts 源码、无 .map)→ 发布 npm → GitHub Release。全程自动,失败即中止。见 生产部署。