“微前端”辨析

理论

微前端:运行时复用方案及其适用场景

微前端这个概念的定义极为混乱,导致社区中谈论微前端时,颇有自说自话的感觉。本文旨在厘清目前社区中存在的对“微前端”一词的不同解释。

总的来说,对微前端的各种解释的一个最大公约数,是指一种在运行时加载欲复用的代码的方法,并且你项目的编译工具并不知道被复用代码的存在,这意味着——待复用的代码虽然未必可以独立使用,但是是可独立部署的(有独立的部署流程,最终有一个可访问的 URL) 。因此传统的“根据路由动态加载组件”之类的方案,甚至更早的 module loader(如 require.js 之类的),虽然也是运行时加载复用代码,但不是微前端方案。

对于以下场景,运行时复用比传统的构建期复用更好:

  • 欲复用的代码源码不在你项目的 repo 里,因此无法在构建期复用。这可能是因为:
    • 代码是其它团队的非公开代码
    • 属于无法合并为 monorepo 的另一个项目
    • 你嫌项目 repo 太大,正把这段代码移往别的 repo
  • 欲复用的代码在你项目的 repo 里,但由于采用了不同的技术栈等原因,构建期复用比较麻烦
  • 欲复用的代码(例如,组件库)实际上被大量不同的项目同时复用,一旦改动,依赖于它的项目都需要重新编译、发布

Dan 认为,微前端方案更像是由于团队原因而做的技术上的迂回。

qiankun creator 的这篇文章也指出了微前端本质是个团队架构问题。

微前端的两种主流解释

现阶段(2021年底),在上述公约数的基础之上,社区里对“微前端”一词有两种主流解释。这两种解释的区别在于代码的复用粒度。

  • 解释一:微前端 = 运行时动态加载执行 JS 模块。在英文社区中,由后端术语“micro-service 借鉴而来的术语 “micro-frontend” 基本上是指这种解释
  • 解释二:微前端 = 运行时动态加载执行 App。在中文社区中,受 qiankun 的影响,术语“微前端”基本是指这种解释
    • 代表实现:qiankun
    • 框架定位:升级版的 iframe

搜索社区文章时应当注意,有些文章(通常是英文社区的文章)使用解释一;有些文章使用解释二(通常是中文社区的文章)。有些文章混用了两种解释。

联系

这两种解释并未泾渭分明,而是有所联系的——App 级的复用粒度,也可以视为模块级复用(将 main.js 视为模块)。正因如此,qiankun 是基于 single-SPA 的封装。

区别

直接动机

  • 模块级复用(single-SPA):由于工程原因,你需要跨 repo 或跨技术栈的代码模块复用
  • App 级复用(qiankun):因为存量的业务原因,你需要集成多个现有的独立 App;因为存量的业务或工程原因,你想拆分一个大 App 为多个小的独立 App,再集成

主要关注点

微前端的其它解释

  • 宏大叙事型:常见于英语社区中。大体上描述了某种前后端协同渲染、分发页面组件的方案,本文不进行详细介绍,可以参阅:
  • 待续…

牢记:微前端不可作为业务架构选型的一种选项!

正如前文反复强调的那样,微前端方案(无论何种解释),本质上是受工程现状或团队权责问题困扰的无奈之举,是一种解决存量问题的方案,通常不可将其作为全新项目中“进行业务划分的架构选型”的选项(除非你的项目在立项之初就碰到了项目团队的权责问题)。对于新项目,你的真实问题其实是——如何处理领域模块。可参考这几篇:

一句话:在新项目中,考虑引入“微前端”的场景应当是业务无关的性能优化/部署发布流程优化

此处列出一些在我看来,实质上是“试图解决一些本不存在的问题”的方案。它们共同的一个显著特点是,都提供了 CLI 工具供用户在创建新项目时使用,并让用户把这些项目组合起来形成“微前端”:

最后,即使是为处理存量问题,也应该意识到,微前端只是一个选项,而不是标准答案。此外,绝对不能使用任何微前端方案加载不可 100% 信任的第三方代码。

工程

无框架实现

美团的这两篇文章介绍了不使用框架,手动进行 App 级微前端项目改造的过程。

框架实现

框架介绍:single-SPA

更详细的介绍可见 【微前端】single-spa 到底是个什么鬼 一文

single-SPA 的作用

sinle-SPA 的只起一个简单的唯一作用:在运行时用用户给定的加载方法,加载 JS 模块,并执行上面暴露出的生命周期钩子

可见,single-SPA 甚至没提供加载器(loader)的实现(虽然以官方推荐的形式建议大家用 SystemJS)。qiankun 使用了自己实现(而不是 single-SPA 官方推荐的 SystemmJS)的一套基于 umd 格式的加载方案(见源码文件 loader.ts)。

single-SPA 的三类模块

single-SPA 划分了三类可复用的模块:Application、Parcel、Utility

Application Parcel Utility
模块规模 大。通常是某个 App 的 main.js 可大可小
专门的 API 无。用户需自行调用加载逻辑,并正确配置 Webpack 进行加载
根据路由触发加载/卸载
生命周期 single-SPA 自动控制(也支持手动 unload) 手动控制
额外能力 被注入了加载 Parcel 的能力(且自动同步生命周期)

综上,Application 配置简单功能更多,Parcel 控制灵活。基于 single-SPA 的 qiankun ,有时将子应用视为 single-SPA 的 Application(当根据声明式路由进行加载时),有时则是 Parcel(当使用命令式进行加载时)。

框架介绍:qiankun

作为 App 级微前端框架的代表性作品,qiankun 的功能是此类框架的标准功能。可见 【微前端】qiankun 到底是个什么鬼 一文。

类似的框架还有(不出意外,都是国产):

它们的目的基本一致—— 即 App 级复用。个别功能/实现/目标框架略有不同。例如 MicroApp, mfy 主打无侵入性,Afla 主打依赖共享等。

依赖共享及其方案

依赖共享指的是,当用微前端方案在运行时加载模块 / App 时,防止重复加载相同的内容(如模块、依赖库等等)。甚至有人认为,微前端基本上等价于依赖共享(这种观点着重强调低运行时开销的复用能力)。

此处介绍依赖共享的两种实现方案(这两种方案可任意与 single-spa / qiankun或其它微前端框架进行集成):