dev.sh

谢明_技术达人
2025-12-24 17:05
阅读 2823

微前端不是银弹,但救了我们的双11

去年双11前两周,我差点把键盘扔出窗外。

事情是这样的:我们公司是个典型的三线城市互联网团队,做本地生活服务平台,产品线杂、人手紧、需求多得像韭菜——割完一茬又长一茬。当时主站用的是 React + Ant Design,前端代码已经膨胀到 80 多个页面,打包后 vendor chunk 超过 3.5MB(gzip 后也有 1.2MB),首屏加载在低端安卓机上经常卡成 PPT。产品经理小李还天天催:“老板说要加一个独立的商家运营后台,下个月上线!”

我说:“咱这单体应用都快散架了,再塞新模块怕是要崩。”

他眨眨眼:“你不是技术负责人吗?搞不定就别当‘负责人’了。”

行吧,被逼上梁山。正好那会儿我在家远程办公,边听 Lo-fi Beats 边刷 GitHub,偶然看到几个开源微前端方案——qiankun、Module Federation、Piral……脑子一热:要不试试微前端?


为什么选微前端?不是为了“时髦”

说实话,我对“架构潮流”一直挺警惕的。之前有同事提议上 WebAssembly,我说:“咱们连 SSR 都没跑通,先别整花活。”但这次不一样。

痛点太真实了:

  • 团队并行开发难:两个小组改同一个 Git 仓库,PR 冲突频发,Code Review 动不动就拖三天。
  • 部署耦合严重:改了个按钮颜色,全站重新构建部署,测试回归成本高。
  • 技术栈僵化:老项目用 React 16,想用新特性(比如 Concurrent Mode)?门都没有。
  • 性能瓶颈:用户进首页,却要把整个商家管理、订单系统、营销活动的 JS 全下载下来。

微前端的核心价值,不是“拆”,而是“解耦”。每个子应用独立开发、独立部署、独立运行,主应用只负责路由分发和沙箱隔离。听起来像微服务?对,但它跑在浏览器里。


技术选型:GitHub 上淘金

我花了三天时间,在 GitHub 上对比主流方案:

方案 加载方式 沙箱能力 子应用通信 支持框架 学习曲线
qiankun (蚂蚁) JS Entry / HTML Entry 强(JS 沙箱 + CSS 隔离) 全局状态 + 自定义事件 任意(React/Vue/Angular) 中等
Webpack Module Federation 构建时联邦 弱(依赖构建配置) import() + shared module Webpack 5+
single-spa 路由驱动 无(需自行处理) customEvent / props 任意

我们最终选了 qiankun。原因很现实:

  1. 我们团队 JavaScript 水平参差不齐,Module Federation 需要深入理解 Webpack 5,风险太高;
  2. single-spa 没有内置沙箱,CSS 样式污染问题得自己兜底,我可不想半夜被叫起来修“按钮变蓝了”的 bug;
  3. qiankun 文档全、社区活跃,GitHub 上 Star 超 20k,出了问题能快速搜到解决方案。

而且,它支持 HTML Entry ——子应用只要暴露一个 index.html,主应用就能动态加载,连构建产物都不用关心。对我们这种“历史包袱重”的项目太友好了。


实战:从单体到微前端的“缝合术”

第一步:主应用改造

主应用保留核心布局(Header + Sidebar + Main),用 registerMicroApps 注册子应用:

// main.js
import { registerMicroApps, start } from 'qiankun';

registerMicroApps([
  {
    name: 'merchant-app', // 子应用名称
    entry: '//localhost:3001', // 开发环境地址
    container: '#subapp-container', // 挂载点
    activeRule: '/merchant', // 路由匹配规则
  },
  {
    name: 'marketing-app',
    entry: '//localhost:3002',
    container: '#subapp-container',
    activeRule: '/marketing',
  }
]);

start({
  sandbox: { strictStyleIsolation: true }, // 开启严格样式隔离
});

注意:线上环境 entry 要换成 CDN 地址,比如 https://cdn.ourcompany.com/merchant/latest/index.html

第二步:子应用适配

子应用几乎不用大改!只需导出三个生命周期函数:

// merchant-app/src/main.js
let app = null;

export async function bootstrap() {
  console.log('merchant app bootstrap');
}

export async function mount(props) {
  app = createApp(App);
  app.mount('#merchant-root');
}

export async function unmount() {
  app.unmount();
}

重点来了:子应用必须能独立运行!我们在 package.json 里加了个判断:

{
  "scripts": {
    "dev": "cross-env IS_MICRO=false react-scripts start",
    "dev:micro": "cross-env IS_MICRO=true react-scripts start"
  }
}

然后在入口文件里:

// index.js
if (!window.__POWERED_BY_QIANKUN__) {
  // 独立运行
  ReactDOM.render(<App />, document.getElementById('root'));
} else {
  // 作为子应用,只导出生命周期
  // ...
}

这样开发时能单独启动调试,不用每次都跑主应用。


踩坑实录:那些让我想砸电脑的瞬间

坑1:CSS 样式污染

虽然开了 strictStyleIsolation,但子应用用了全局 CSS Reset,还是把主站字体干没了。后来强制要求所有子应用使用 CSS ModulesScoped CSS,并在 CI 流程里加了 ESLint 规则:禁止 .css 文件中出现非局部类名。

坑2:公共依赖重复加载

主应用和子应用都用了 React 17,结果浏览器加载了两份 React,内存直接翻倍。解决方案:在 start() 里配置 singular: true(确保同一时间只有一个子应用激活),并通过 external 共享

// 主应用 webpack.config.js
module.exports = {
  externals: {
    react: 'React',
    'react-dom': 'ReactDOM'
  }
};

子应用也做同样处理,并通过 <script> 在主 HTML 中提前引入 React。

坑3:本地联调地狱

三个子应用 + 主应用,五个终端同时跑,端口冲突、跨域报错、缓存失效……后来写了个 shell 脚本一键启动:

concurrently \
  "cd main && npm run dev" \
  "cd merchant-app && npm run dev:micro" \
  "cd marketing-app && npm run dev:micro"

配合 concurrentlywait-on,终于不用手动开 N 个 terminal 了。


效果:性能提升 + 团队效率起飞

上线三个月后,数据说话:

指标 改造前 改造后 提升
首屏加载 (3G) 4.2s 1.8s ↓57%
JS Bundle Size 3.5MB 0.9MB (主应用) ↓74%
部署频率 1次/周 3-5次/天(子应用独立发布) ↑500%
PR 冲突率 高频 几乎为零

更重要的是,新来的实习生也能快速上手商家后台模块,不用再啃 20 万行的 monorepo。产品经理小李现在见我就笑:“你们技术真牛,上次改需求,当天就上线了!”


关于安全,我多啰嗦几句

微前端放大了攻击面——子应用可能来自不同团队,甚至第三方供应商。我们做了三件事:

  1. CSP 限制:主应用设置严格的 Content-Security-Policy,禁止 inline script;
  2. Entry 白名单:子应用 entry URL 必须走公司内网或可信 CDN,禁止任意域名;
  3. 沙箱加固:开启 sandbox: { experimentalStyleIsolation: true },防止 CSS 劫持。

别觉得 paranoid,去年某大厂就因为微前端没隔离好,导致 XSS 跨子应用传播。安全不是功能,是底线。


写在最后:微前端适合你吗?

如果你的项目满足以下任一条件,可以考虑微前端:

  • 团队超过 10 人,多个小组并行开发;
  • 应用模块边界清晰(如 C 端 / B 端 / 运营后台);
  • 有遗留系统需要渐进式重构;
  • 对首屏性能有强要求。

但如果你只是做一个内部管理后台,就别折腾了——微前端解决的是复杂度问题,不是代码质量问题。我见过有人为了用 qiankun,硬把一个 5 个页面的应用拆成 3 个子应用,结果维护成本翻倍,纯属自虐。

我现在每天在家撸代码,听着音乐,看着子应用独立部署的日志流水,感觉世界清净多了。上周五晚上十点,收到一条告警:商家后台 404。我淡定地查了下,发现是子应用 CDN 配置错了——只影响该模块,主站稳如老狗。修完 bug,继续听我的《Coding Jazz》,舒服。

技术没有银弹,但合适的架构,真的能让你少掉几根头发。共勉。

本文代码示例已脱敏并上传至 GitHub 私有仓库(公司政策),如有兴趣可私信交流。
—— 一个在三线城市边听歌边写 React 的技术负责人

评论 0

最热最新
暂无评论
谢明_技术达人Lv.1
0
影响力
0
文章
0
粉丝