主题
02 · 微前端:场景、方案与代价
目标:决策向——知道何时不该上微前端;能对比 iframe / Module Federation / qiankun / Web Components;讲清路由、样式、公共依赖的代价。
1. 背景与目标
面试常问「你们怎么做多团队前端协作?」——默认答案不该是「上微前端」。Journal 已是 monorepo:client(uni-app)、admin(React)、backend 同仓不同应用,模块边界靠 package + 构建产物,多数场景比微前端更简单。
微前端解决的是:多个独立构建、独立部署的前端应用,在浏览器里拼成一张「大产品」,且团队能各自发版。若你只是「一个大 SPA 拆文件夹」,用路由懒加载 + monorepo 共享包即可。
2. 何时该 / 不该
| 适合考虑微前端 | 更该用 monorepo / 模块化 SPA |
|---|---|
| 多团队、不同技术栈、不同发布火车 | 同一技术栈、同一发布节奏 |
| 遗留系统无法重写,只能嵌入 | 绿field 或可控重构 |
| 子应用由外包 / 子公司交付 | 全在自己仓库里 |
| 强隔离:子应用崩了不能拖死主应用 | 隔离需求可通过 iframe 沙箱或错误边界解决 |
默认建议:先 monorepo + 路由分包 + 设计系统;只有组织与发布约束逼你拆运行时,再选微前端方案。
3. 方案对照
| 方案 | 隔离 | 集成方式 | 优点 | 代价 |
|---|---|---|---|---|
| iframe | 最强(独立 JS/CSS 上下文) | <iframe src> | 实现快、样式零污染 | 路由同步难、弹层/全屏受限、双滚动条、通信 postMessage 啰嗦 |
| Web Components | 中(Shadow DOM 可隔样式) | 自定义元素 | 标准、框架无关 | 生态碎片、与 React/Vue 事件/属性桥接成本高 |
| Module Federation | 弱(共享运行时) | Webpack/Rspack 远程模块 | 共享依赖、接近原生集成 | 构建链绑定、版本契约、本地联调复杂 |
| qiankun / wujie | 中~强 | 沙箱 + 生命周期钩子 | 国内文档多、Vue/React 都接 | 仍要处理路由/资源路径;升级框架要回归 |
没有「最好」,只有「你的组织痛点匹配哪条代价」。
4. 心智模型:Host + 1 Remote(极简)
text
┌─────────────────────────────────────┐
│ Host(主应用,掌控壳子与基座路由) │
│ ┌─────────────┐ ┌───────────────┐ │
│ │ 自有页面 │ │ 子应用挂载点 │ │
│ │ /dashboard │ │ #subapp-root │ │
│ └─────────────┘ └───────┬───────┘ │
└───────────────────────────┼─────────┘
│ 加载 remoteEntry.js
▼
┌───────────────┐
│ Remote 子应用 │
│ 独立 build/deploy│
└───────────────┘1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
Host 负责:顶栏、登录态、全局路由前缀、子应用 mount / unmount。Remote 负责:业务页面,不应假设自己拥有整页 URL(除非约定 /app-a/* 前缀)。
Module Federation 伪代码(概念级,不必手敲生产配置):
js
// host webpack.config — remotes 声明
remotes: { shop: 'shop@https://cdn.example.com/remoteEntry.js' }
// host 页面里动态消费
const ShopApp = React.lazy(() => import('shop/App'))1
2
3
4
5
2
3
4
5
qiankun 则是注册子应用入口 URL + 激活规则 activeRule: '/shop';框架帮你做 JS 沙箱与样式隔离(仍可能漏)。
5. 必踩四坑
5.1 路由
- 浏览器地址栏只有一个
history:主应用vue-router/react-router与子应用路由谁优先? - 默认做法:约定前缀
/legacy/*归子应用;Host 在 prefix 内不再抢路由;子应用base与publicPath对齐部署路径。
5.2 样式
- 全局
reset、Tailwindpreflight、Ant Design 变量会互相覆盖。 - iframe 最省心;JS 沙箱方案要测 z-index、弹层 teleport 到
body是否逃逸。
5.3 公共依赖
- 两套 React 17/18 同时加载 → hooks 报错。Federation 可
shared: { react: { singleton: true } },但版本区间要契约化。 - 能共享就共享、不能共享就 iframe——中间态最折磨人。
5.4 鉴权与埋点
- Token 在 Host 刷新,Remote 仍用旧 Token 发请求 → 401 风暴。
- 埋点 SDK 初始化一次还是 N 次?错误监控如何区分子应用来源?
6. 与 Journal 的对照
| Journal 现状 | 微前端式做法 |
|---|---|
admin 与 client 不同构建、不同域名部署 | 若硬塞进同一页,才需要运行时集成 |
| 共享后端 API、OpenAPI | 契约在 HTTP 层,不靠前端运行时拼 |
| monorepo 统一 PR 改 API + 两端 | 微前端适合「子应用本周发、主应用下周发」 |
结论:Journal 不需要微前端架构;把本篇当面试「架构取舍」题即可。
7. 验收清单
- [ ] 能列举 2 条「不该上微前端」的理由
- [ ] 完成一页方案对照(本文表格即可),能口述 iframe vs Federation 核心差异
- [ ] 能讲清路由前缀、公共依赖 singleton、样式隔离各对应什么坑
- [ ] (可选)画一张 Host + Remote 数据流/路由图,不要求跑 demo
