微前端 Module Federation 实战:12min → 3min 构建优化

0 0

前言

做前端架构的人要不要懂微前端?我的回答是 ——不是去用 qiankun / Module Federation,而是建立”为什么需要把单仓变成多仓”的工程判断。原因有三:

  1. 简历里”12min → 3min 构建优化”是简历里 Module Federation 实战。单仓巨型 monorepo 用 MF 拆子应用,构建时间数量级下降
  2. 微前端不是”为了拆而拆”超过 50 个开发者 / 5 个子团队才考虑微前端,小项目 monorepo + 路由懒加载就够了
  3. 三大方案底层都是 iframe + JS 沙箱。qiankun / micro-app / wujie 思想一脉相承,选型决策比写代码重要

这一篇是『前端架构修仙路』的第 25 篇。我跳过具体 API(不讲 ModuleFederationPlugin 怎么配),用架构图 + 三大方案对比 + 真实案例,把微前端原理 + 选型决策讲透。下一篇深度聊低代码平台设计。

一、为什么需要微前端

传统单仓 monorepo:
  ✓ 简单(一个仓库,一个构建,一个部署)
  ✗ 50+ 开发者 = 合并冲突地狱
  ✗ 巨型 bundle = 构建 12min
  ✗ 一次发版 = 整个 app 上线(业务方不同步)
  ✗ 跨框架困难(Vue / React 难混用)

微前端:
  ✓ 独立部署(业务 A / B / C 各自发版)
  ✓ 独立构建(每个子应用 < 2min)
  ✓ 跨框架(主 Vue / 子 React 都能用)
  ✗ 运行时隔离(iframe 性能损耗)
  ✗ 调试复杂

架构师心法不到 50 开发者 + 5 子团队 别用微前端小项目 monorepo + 路由懒加载就够

二、三大方案对比

方案底层跨框架性能适合场景
qiankuniframe + JS 沙箱损耗较大多团队 / 跨框架 / 强隔离
micro-appiframe + Web Components京东电商场景
wujieiframe + Web Components较好腾讯场景
Module FederationJS 共享⚠️ 同构最好同框架 + 共享运行时

架构师决策

  • 跨框架 + 强隔离 → qiankun / wujie(iframe 沙箱)
  • 同框架 + 共享运行时 → Module Federation(Webpack 5 / Vite)
  • 京东系 → micro-app

三、qiankun 实战

// 主应用 (main app)
import { registerMicroApps, start } from 'qiankun';

registerMicroApps([
  {
    name: 'finance',
    entry: '//finance.example.com',
    container: '#subapp-container',
    activeRule: '/finance',
  },
  {
    name: 'hr',
    entry: '//hr.example.com',
    container: '#subapp-container',
    activeRule: '/hr',
  },
]);

start();

// 子应用 (finance app)
export async function bootstrap() { /* 启动钩子 */ }
export async function mount(props) { /* 挂载到 #subapp-container */ }
export async function unmount() { /* 卸载 */ }

核心机制:iframe + proxy 沙箱 + import-html-entry 解析子应用 HTML。

  • JS 沙箱:Proxy 代理 window 上的全局变量
  • 样式隔离:动态插入 <style> 标签 + scoped CSS
  • 通信:基于 props + CustomEvent / initGlobalState

四、Module Federation 实战(顺丰 ERP)

简历里出现 “ERP 重构 12min → 3min”——核心改造就是用 Webpack 5 Module Federation。

4.1 重构前

erp-app (monorepo)
  ├── apps/admin/      # 主应用(800+ 页面)
  ├── packages/ui/     # FinUI 组件库
  ├── packages/utils/   # 工具函数
  ├── packages/sdk/     # 数据 SDK
  └── ...
  
pnpm -r build:    12min

痛点

  • apps/admin 改 1 行 → 12min 全部 build
  • 不能并行构建(共享 chunk 互相依赖)
  • 部署发版原子化(admin 改了 utils 也得发版)

4.2 重构后(Module Federation)

erp-app
  ├── apps/admin/      # Shell (只 100KB,秒开)
  ├── apps/finance/    # 独立子应用 (deploy: 1.5min)
  ├── apps/hr/         # 独立子应用 (deploy: 1.2min)
  ├── apps/crm/        # 独立子应用 (deploy: 1.8min)
  └── packages/shared/ # 共享依赖 (React / Antd / utils)

Shell 配置

new ModuleFederationPlugin({
  name: 'admin',
  remotes: {
    finance: 'finance@//finance.example.com/remoteEntry.js',
    hr: 'hr@//hr.example.com/remoteEntry.js',
  },
  shared: {
    react: { singleton: true },
    'react-dom': { singleton: true },
    antd: { singleton: true },
  },
});

// Shell 引用子应用
const FinanceApp = React.lazy(() => import('finance/App'));

收益

  • Shell 构建 30s(只编译 admin 本身)
  • 子应用独立构建 1.5min(只编译 finance)
  • 并行构建:admin / finance / hr / crm 同时跑 = 1.5min 总耗时
  • 共享 React / antd = 每个子应用 bundle 减 200KB

4.3 真实数据对比

指标重构前重构后
全量构建12min1.5min(并行)
修改 admin 后构建12min30s
修改 finance 后构建12min1.5min
Bundle size (主 app)800KB100KB
独立部署
跨团队并行

五、运行时隔离:iframe vs JS 沙箱

维度iframe 沙箱JS 沙箱 (with-sandbox)
JS 隔离100%(独立 window)⚠️ 99%(Proxy 拦截)
CSS 隔离100%(独立 document)⚠️ 90%(scoped / namespace)
全局变量污染(需要清空)
性能损耗5-15% (iframe)< 1%
跨子应用通信复杂(postMessage)简单(globalState)

架构师决策

  • 强隔离 + 跨框架 → iframe 沙箱(qiankun / wujie)
  • 同框架 + 共享运行时 → JS 沙箱(Module Federation / Vite Module Graph)

六、踩坑提醒(资深架构师请重点看)

  1. 不要在小项目用微前端10 个页面 / 5 个开发者的项目用微前端 = 杀鸡用牛刀。monorepo + 路由懒加载就够
  2. 不要用 JS 沙箱跑跨框架。qiankun 的 Proxy 沙箱对 React 不友好——React 18+ concurrent 模式 + Proxy 拦截的兼容性问题。跨框架必用 iframe 沙箱
  3. 不要让子应用过大。每个子应用 200+ 页面 = 微前端没意义(应该再拆)。单子应用 50-100 页面是甜点
  4. 不要在微前端里共享太多依赖。MF 共享 React / Vue 没问题,共享业务 utils = 重新耦合共享 = 基础 runtime,业务 utils 各包独立
  5. 不要忽略部署复杂度。微前端 = N 个子应用部署CI / CDN / 灰度 / 回滚复杂度 × N。架构师必须提前设计

总结

这一篇用 6 个关键事实把微前端串起来:

  • 不到 50 开发者 / 5 子团队别用微前端——单仓 monorepo + 路由懒加载够用。
  • 三大方案:qiankun (iframe + 跨框架) / micro-app (京东系) / wujie (腾讯系) / Module Federation (同框架共享)。
  • Module Federation 实战:Shell + 子应用,Shell 30s,子应用 1.5min,全量并行 1.5min 总耗时。
  • 运行时隔离:iframe 100% 隔离 (性能 5-15%) / JS 沙箱 99% 隔离 (性能 < 1%)。
  • 跨框架 + 强隔离 → iframe;同框架 + 共享运行时 → MF。
  • 生产案例:顺丰 ERP 12min → 1.5min 提速 8 倍,bundle 减 87%。

下一篇:低代码平台设计——表单 / 流程 / 报表的代码生成,ERP 半低代码项目实战。

5 道重点面试问题方向

Q1(答案):什么场景必须用微前端?为什么不到 50 开发者别用?

A:必须用微前端的场景:① 50+ 开发者 + 5 子团队同时维护一个产品;② 不同业务线独立发版(财务 / 人力 / 客户 节奏不同);③ 跨框架(主 Vue 子 React,需要并存);④ 巨型构建慢(单仓 12min +)。不到 50 开发者别用:10 个页面 / 5 个开发者的项目用微前端 = 杀鸡用牛刀,monorepo + 路由懒加载就够,微前端 5-15% 性能损耗 + 调试复杂 + 部署 × N,小项目承受不起架构师心法:微前端是组织问题的技术方案,不是技术问题的技术方案

Q2(思考):qiankun / micro-app / wujie / Module Federation 怎么选?

A:选型决策:① 跨框架 + 强隔离qiankun / wujie (iframe 沙箱);② 同框架 + 共享运行时Module Federation (Webpack 5 / Vite);③ 京东系项目micro-app;④ 腾讯系项目wujie核心决策点:跨框架必 iframe(qiankun/wujie),同框架用 MF(性能 5 倍,共享运行时)。生产案例:顺丰 ERP 5 个业务域,Vue 3 统一,用 Module Federation;某 ToB SaaS Vue / React 混用,用 qiankun iframe

Q3(思考):Module Federation 是怎么实现「运行时共享依赖,构建时独立」的?Shell + 子应用的构建配置怎么写?

A:核心原理:Webpack / Rspack 编译时把共享依赖(React / Antd)标记为 singleton(只加载一份),Shell 启动时异步加载子应用的 remoteEntry.js,按需动态 importShell 配置:new ModuleFederationPlugin({ name: 'admin', remotes: { finance: '...' }, shared: { react: { singleton: true } } });子应用配置:new ModuleFederationPlugin({ name: 'finance', filename: 'remoteEntry.js', exposes: { './App': './src/App' } })生产数据:Shell bundle 800KB → 100KB(共享依赖只下 1 次),子应用独立部署,Shell 30s,子应用 1.5min,全量并行 1.5min 总耗时。

Q4(思考):qiankun 的 iframe 沙箱 vs Module Federation 的 JS 沙箱,性能 / 隔离性怎么权衡?

A:iframe 沙箱:100% JS / CSS 隔离(独立 window/document),性能损耗 5-15%(iframe 创建 + postMessage 通信);JS 沙箱(MF):99% 隔离(Proxy 拦截 + scoped CSS),性能损耗 < 1%(共享 runtime + 零序列化)。选型:强隔离 + 跨框架 用 iframe,同框架 + 共享运行时 用 JS 沙箱。生产数据:qiankun 多子应用 + 跨框架,首屏 1500ms;MF 同框架,首屏 800ms

Q5(思考):你在顺丰 ERP 项目里是怎么从单仓 monorepo 迁移到 Module Federation 的?踩过哪些坑?

A:迁移三步:① 识别业务边界 — 财务 / 人力 / 客户 / 主应用,确定子应用划分;② 共享依赖抽取 — React / Antd / utils / SDK 抽到 packages/shared,singleton 配置;③ Shell + 子应用拆分 — 主应用变 Shell 只挂路由,业务页面拆到子应用,exposes 暴露入口。踩坑:① shared 配置 太激进导致版本冲突,改成精确到子集;② CSS 隔离data-app 属性 + scoped,不用 css-modules(太重);③ 部署流水线 重写,每个子应用独立 CI + 独立 CDN 路径;④ 灰度发布 用 Shell 路由 + 子应用版本号,Shell 决定调用哪个版本。

💡 每道题后面都有 AI 助手按钮,一键拿到详细答案。

参考资料

🔗 原文链接 分享让更多人看到

评论