微前端初探
Published on Jul 12, 2023, with 73 view(s) and 0 comment(s)
Ai 摘要:微前端(Micro Frontends)是将大型前端应用拆分为多个独立开发、部署的子应用,各子应用可并行开发并整合至主应用统一呈现,其核心理念包括独立性、技术栈无关性、主应用统一管理及运行时集成。典型场景包括多团队协作开发、频繁更新模块及多技术栈共存需求。相比传统单体架构,微前端能解决团队协作冲突、构建时间长等问题,但初期可能增加复杂度。常见技术方案有Qiankun、Single-SPA、Webpack的Module Federation及iframe,各有优缺点。

微前端(Micro Frontends)” 是将大型前端应用拆分成多个独立开发、独立部署的小型应用,每个小应用负责一部分功能,多个前端团队可以并行开发、独立发布各自的子应用,最终整合在一个主应用中统一呈现。

这个理念是借鉴“微服务”在后端的思想,但应用于前端架构。

微前端核心理念

  • 独立性: 每个子应用可以独立开发、构建、部署
  • 技术栈无关: 不同子应用可以用 React/Vue/Angular 等不同框架
  • 主应用统一管理路由/UI: 主应用负责页面路由分发和整体布局
  • 运行时集成: 子应用在运行时动态加载(而不是构建时打包在一起)

典型使用场景

  • 多团队协同开发大型前端系统(如电商后台、CMS、SaaS平台)
  • 系统模块更新频繁,部署希望低耦合
  • 需要支持不同技术栈或版本共存

优点(不使用微前端)

  • 开发简单:不需要拆分子应用,不用考虑通信、隔离等复杂问题
  • 构建部署流程统一:一次构建,一次部署,流程清晰
  • 调试方便:不存在跨子应用跳转或版本冲突问题
  • 性能更好(初期):无需动态加载多个子应用资源,初始加载更快
  • 技术栈统一:不存在多个框架共存问题(如 React + Vue)

缺点(当项目变大时)

  • 团队协作冲突大:多团队同时改动一个项目,易冲突,CI/CD难以并行
  • 构建时间越来越长:代码体积庞大,构建几分钟起步
  • 更新粒度粗:改一个小功能也要重新构建整个项目并全量上线
  • 技术升级困难:想把 Vue2 升级到 Vue3,牵一发动全身
  • 难以复用已有系统模块:多系统难以共享模块或 UI

微前端技术方案

方案简介优点缺点
Qiankun基于 Single-SPA,阿里出品的微前端框架成熟、支持多框架、文档完善框架较重,子应用需适配
Single-SPA最早的微前端框架之一灵活、社区强上手略复杂
Module Federation(Webpack 5)原生支持模块共享轻量、适合模块共享需要 Webpack 5
iframe每个子应用放在 iframe 中完全隔离、简单实现用户体验差、通信麻烦

为什么不用iframe

1. 先说优点(为什么很多人会想到 iframe)

  • 天然隔离:iframe 天然能隔离 CSS、JS 作用域,避免子应用相互污染。
  • 安全性:不同应用在独立的渲染上下文运行,跨站安全问题更容易控制。
  • 上手简单:直接 <iframe src="xxx"> 就能加载一个子应用。

2. iframe 的缺点(导致不被推荐)

  1. 用户体验差
    • 每个子应用都是独立文档,页面切换会闪烁、白屏
    • iframe 内的内容无法自然适配父应用的 滚动、布局
  2. 路由与刷新问题
    • iframe 有独立的路由体系,无法和浏览器地址栏同步,不利于前端路由统一管理(例如刷新、前进、后退行为会失效)。
  3. 跨应用通信困难
    • 父子应用通信要靠 postMessage,相比于 JS 沙箱、共享事件总线等机制,不够灵活高效
  4. SEO 不友好
    • 搜索引擎对 iframe 内容抓取有限,不利于 SEO。
  5. 样式和交互割裂
    • 子应用和主应用之间的样式、弹窗、全局快捷键、右键菜单等都无法无缝衔接,用户体验不一致
  6. 性能问题
    • iframe 会占用较多资源,每个子应用都要单独创建浏览器上下文,内存和加载性能差

基于 JS 沙箱的微前端隔离方案

JS 沙箱的目标:
👉 在同一个页面里运行多个子应用,但互不干扰

1. Proxy 代理 window

  • 通过 ES6 Proxy 拦截子应用对 window 的读写操作;
  • 每个子应用获得一个“假的 window”(proxy 对象),只在自己的作用域生效;
  • 例如:

    const fakeWindow = new Proxy(window, {
      get(target, key) {
        return target[key];
      },
      set(target, key, value) {
        // 只修改沙箱环境,不污染真实 window
        targetSandbox[key] = value;
        return true;
      }
    });
    
  • 子应用执行 window.a = 1,只会存在于自己的沙箱,不会污染主应用或其他子应用。

2. with + eval 改变执行上下文

  • 通过 with (proxy) { eval(code) } 的方式,强制子应用代码在 proxy 环境下运行;
  • 这样,子应用里的所有变量查找,都会优先从 sandbox(Proxy)里取。

3. 生命周期控制

  • qiankun 在子应用 mount/unmount 时,会:
    • 激活沙箱(打开 Proxy 代理);
    • 清理子应用注册的全局变量和副作用(如定时器、事件监听)。

4. 样式隔离(配合 Shadow DOM 或样式前缀)

  • JS 沙箱解决的是 全局对象污染
  • CSS 冲突 qiankun 会通过 动态样式隔离 解决,比如:
    • scoped css / Shadow DOM
    • 或运行时给子应用样式加上前缀。