为什么需要微前端

单体前端项目到了一定规模就会陷入泥潭:代码库越来越大,构建越来越慢,团队并行开发互相踩线,发版要全量回归。微前端把大前端拆成多个独立开发、独立部署的子应用,由一个主应用负责壳与路由,子应用按需加载,从架构上解耦团队与发布。

微前端的本质是"运行时组合":多个子应用的代码在浏览器里被主应用组织成一个完整产品。它与后端微服务的对应关系并不严格——子应用可以是独立技术栈、独立仓库、独立发布节奏,但共享同一套用户体系与导航壳。

本文核心知识点
  • 主应用负责壳、路由与子应用调度。
  • 子应用独立开发部署,按需挂载。
  • qiankun基于 single-spa 的成熟方案。
  • 模块联邦Webpack 5 的运行时共享。
微前端配图:蓝紫渐变背景四根高度依次递增的六边形渐变柱体并排,柱顶由发光折线灯带依次相连,扁平科技插画
高度各异的柱体各自独立又被顶部连线统摄,正是子应用独立与主应用整合的意象。

微前端三大技术路线

实现微前端有三条主流路线。iframe 最简单:天然隔离样式与脚本,但通信麻烦、体验割裂、弹窗定位与滚动都有历史包袱,适合隔离要求极高的小场景,不适合做核心产品壳。single-spa 是通用微前端框架,管理子应用的注册与生命周期,但样式隔离、通信等都要自己补。

qiankun 是蚂蚁开源的单体框架,基于 single-spa 加 HTML Entry、样式隔离、沙箱与资源预加载,开箱即用,是国内微前端事实标准。模块联邦则是 Webpack 5 的内置能力,构建期声明共享依赖,运行时从一个远程模块图里拉取组件,适合同技术栈团队的组件级共享。

qiankun 主应用接入

主应用用 registerMicroApps 注册子应用:配置 name、entry、container 与 activeRule,路由命中 activeRule 时把子应用挂载到指定容器。用 start 启动,prefetch 默认开启会预拉子应用资源。

import { registerMicroApps, start } from "qiankun";
registerMicroApps([
  {
    name: "order",
    entry: "//order.example.com",
    container: "#subapp-container",
    activeRule: "/order",
  },
  {
    name: "user",
    entry: "//user.example.com",
    container: "#subapp-container",
    activeRule: "/user",
  },
]);
start({ prefetch: true });

主应用的基座里,导航与用户态要设计成全局能力:子应用通过主应用暴露的全局对象拿用户信息、跳转路由、打开弹窗。基座的稳定性直接影响全部子应用,主应用要小、要稳,尽量不随业务迭代大改。

子应用接入与生命周期

子应用要导出生命周期钩子:bootstrap 初始化一次,mount 挂载渲染,unmount 卸载清理。qiankun 通过 HTML Entry 加载子应用的 HTML,自动执行其中的脚本,子应用要暴露这些钩子并配置 publicPath 支持运行时设置资源路径。

// 子应用 main.js 示例(Vue)
let instance;
export async function bootstrap() {}
export async function mount(props) {
  instance = new Vue({ router, render: h => h(App) }).$mount("#app");
}
export async function unmount() {
  instance.$destroy();
  instance.$el.innerHTML = "";
}

生命周期最容易踩的坑:unmount 只销毁框架实例不清理副作用,事件监听与全局定时器泄漏,导致子应用反复挂载后内存上涨、事件重复触发。规范是把所有副作用登记在 unmount 里成对清理。

样式隔离与通信

qiankun 默认开启样式隔离,会把子应用的样式限定在容器作用域内;还要约定团队规范:子应用全局样式只写业务不写 reset,组件库样式通过 scoped 或 CSS Modules 处理,避免互相污染。CSS 变量可以作为跨应用的样式契约。

子应用间通信不要用全局变量满天飞。qiankun 提供 props 下发:主应用通过 mount 的 props 传全局状态与 API;复杂场景用全局事件总线或状态管理库,事件名统一命名空间;跨应用调接口统一走主应用暴露的服务,别让子应用直连各自后端,否则用户体系与鉴权会乱。

// 主应用向子应用下发全局能力
start({
  sandbox: { strictStyleIsolation: true },
  global: { userInfo, navigate, openModal }
});

部署与构建

子应用独立部署是微前端的核心收益:每个子应用有自己的仓库、流水线与发布窗口。部署架构上,主应用与各子应用部署到不同路径或不同域名,主应用通过子应用的入口 URL 加载;CDN 上按版本目录管理资源,支持灰度与回滚。

构建上要注意几点:子应用的 publicPath 要用运行时变量,避免写死导致资源 404;公共依赖尽量抽到运行时共享或体积可接受就各自打包;子应用按需拆包,不要一个应用全量打包让首屏变慢;主应用与子应用之间的路由前缀约定清楚,避免冲突。

// webpack 子应用配置要点
output: {
  library: { type: "umd", name: "orderApp" },
  publicPath: "auto",   // 运行时动态资源路径
  jsonpFunction: "webpackJsonp_order",
}