微前端框架初探,对比qiankun和Module-Federation

在微前端领域中,之前我们围绕着 qiankun(single-spa)的方案设计了一套微前端集成部署方案,并在 OPS 项目中得以应用。

随着 webpack5 的更新,现在又有了另一种微前端解决方案,即 module federation。该方案与 single-spa 有什么区别,各自的应用场景以及优势又是什么?

Qiankun vs Module-Federation(MF)

从设计思路,接入方式(框架要求),宿主依赖,应用场景,性能和其他注意事项入手分析两者差异。

微前端定义

微前端官网定义了微前端的概念:

Techniques, strategies and recipes for building a modern web app with multiple teams that can ship features independently.
微前端是一种多个团队通过独立发布功能的方式来共同构建现代化 web 应用的技术手段及方法策略。

他不是一个具体的框架或者标准,但所有的方式都基本满足以下几个特点:

  1. 独立开发,测试,部署
  2. 技术栈无关
  3. 更新后自动同步(运行时集成)

曾经的 iframe 和 umd 模块就是非常典型的微前端,但随着行业的发展,两者存在的问题和局限性也暴露出来,例如 iframe 存在性能问题,子应用弹窗无法在全屏展示等没问题,umd 模块就更加局限,基本上被使用在工具类,函数库的场景

JS Entry vs HTML Entry

在讨论不同的微前端实现方案时,需要先了解两种不同的运行时载入的方法,即子应用应该提供什么样的资源作为加载入口?

JS Entry 顾名思义是将子应用的资源打包成一个 js 文件,主应用通过加载这个 js 文件加载子应用。但这个方法会导致这个入口 js 文件过于庞大,如果依赖了其他 css,图片资源,还需要后续进一步加载,无法并发。即使可以在打包子应用时做成不是单入口的,而是将 js 拆分开来,但这样主应用就需要维护加载逻辑,各个 js 有加载顺序的限制,并发后如何处理异步情况等,会给主应用带来巨大的挑战。

HTML Entry 就无需关心上面的问题,子应用在打包时,可以像正常应用一样打包并且可以做打包优化,最终输出一个 html 文件,主应用只需要加载这个 html 文件并将其放到自身的 html 中,浏览器就会自行按照顺序加载子应用资源,同时解决了并发和单一入口文件过大的问题。同时 HTML 本身也可以携带子应用的部分元素,让子应用更快地展示出来。

在以往的微前端技术中,iframe 就是以 HTML Entry 的形式加载子应用,而 umd 则是已 JS Entry 的形式加载子应用。两者加载方式的不同也导致了适用场景的不同。

在本文讨论的两个方案中,qiankun 主要是以 HTML Entry 的形式加载子应用,但也支持 JS Entry。而 Module-Federation 是以 JS Entry 的形式加载子应用。实际上所有 JS Entry 实现的微前端都相当于是以前 umd 方案的扩展,其本质还是一样的。

设计思路

qiankun 是由主应用和微应用组成,主应用提供了一个基础的应用框架,再由微应用实现各个模块的业务,如图所示:

主应用提供一个“基座”,其中包含了该应用的基础功能,例如功能菜单,用户登录相关,权限相关,核心 API 接口调用等逻辑,子应用无需关心这些底层的复杂逻辑,通过和主应用数据交互拿到自己需要的那一部分数据即可。

而 Module-Federation 没有主应用和子应用的概念,每个应用都可以是主应用,独立运行的同时,将自己应用的一部分暴露出去提供给其他应用使用。

这种设计模式可以让业务方实现一个“去中心化”的应用部署群,每个应用都可以引用其他应用的模块,而这个模块可大可小,可以是一个函数,也可以是一个 vue 组件,甚至可以是一个页面。

接入方式

qiankun 的接入方式更接近于传统的 iframe 模式,即采用 HTML Entry 加载子应用。主应用会将子应用的 html 下载下来并插入到自身的 html 中去,子应用 html 中的 script 标签也会按顺序下载执行。

qiankun 实现了 js 沙箱机制,保证了各个应用之间的运行环境互相隔离,window 对象是用 proxy 代理,在子应用加载和卸载的时候框架会自动保存/还原当前的环境快照,样式则是通过 scope 或者 shadow dom 的形式进行隔离。

由于 qiankun 的沙箱机制,保证各个 app 运行在不同的环境下(类似 iframe),故接入没有框架限制,应用也无需大规模改造,非常适合老项目平滑升级,也适合巨石应用拆分。

MF 由于是 webpack5 新引入的特性,所以不论是模块提供方还是引用方都需要使用 webpack5 进行打包,这对项目改造和平滑升级带来了比较大的难度和工作量(接入方式在下一篇文章介绍)。

MF 采用 JS Entry 的形式,实际上与之前的 UMD 模式并没有太大的区别,只不过使用 webpack 自己的模块加载器实现,除此之外,与传统的 UMD 模式还有以下的区别:

  1. 传统 UMD 模块一般使用 script 标签引入,注入到全局 windows 对象上,这种方式能够独立部署,动态更新(注意 CDN 缓存)
  2. 使用 webpack 引入 UMD,需要通过 imports-loader 特殊处理,这种方式需要跟随项目一起构建,没办法动态部署

MF 像是结合了两种方式的优点,既可以像正常模块一样直接 require,但在运行时直接从网络加载,实现动态更新。

其实本来 UMD 就不是为了微前端设计的,所以很多第三方库在发布的时候都会携带上版本号(至少是大版本号),为的是保证向上运行的稳定,但也注定了其必定不会过于“动态”,无法做到实时更新。

MF 在接入的时候也需要注意缓存问题,与 HTML Entry 不同,静态资源(jss,css)一般都存在强缓存(主要是 CDN),这就导致即使模块提供方更新了内容,由于模块入口文件缓存,宿主应用也无法及时更新,当然 webpack5 也提供了相应的解决办法,这个我们也在之后讨论。

总之,我们可以将 qiankun 的接入方式理解成“应用”级别的接入,而 MF 则是“组件”级别的接入(组件功能可大可小),只不过同时都有运行时加载这一特性。

宿主依赖

由于 qiankun 实现了环境隔离,子应用不依赖宿主任何环境,如果业务上需要可以通过 props 或者 globalState 进行传递。这种方式虽然大大降低了对接成本,但也造成了一部分重复依赖,例如父子应用依赖的模块没办法共用,一些底层的框架,例如 vue,lodash 等会被重复加载。

当然想要共用一些第三方依赖库也可以通过微应用配置 external 的形式,然后在主应用导入这些依赖,但这与 qiankun 设计的环境隔离的思路相违背,因此官方并不建议这样做。

而 MF 根据封装功能模块的不同,会依赖于宿主应用的运行时。如果 MF 暴露的模块显示依赖某些第三方库,webpack 在打包时会自动收集这些依赖,宿主应用引入这个 MF 模块时也会将这些依赖引入进来,但由于缺乏沙箱机制,有可能会引发一些问题。

例如 vue-router 是依赖浏览器底层的 historyAPI 的,通过拦截 popstate 事件做到自定义路由跳转,这类的第三方依赖只能注册并运行一次。当然 qiankun 也会遇到类似的问题,但其只需要注意父子应用使用不同版本的 vue-router 导致不兼容的情况,同版本还是可以放心使用的。

MF 支持远程模块和宿主模块共用第三方依赖,而且应该优先配置第三方依赖,当远程模块的依赖宿主没有时则会远程拉取,如果存在则直接使用宿主的依赖,可以提高性能,如果有类似 vue-router 之类只能加载一次的依赖包,则可以配置 singleton: true 使其只加载一次。

性能

qiankun 设计模式下,由于父子应用独立运行,子应用所有依赖都需要下载,并没有分包优化,性能会有所退化。另外 qiankun2.0 使用 proxy 实现沙箱会有巨大的性能损耗。

MF 理论上还是基于 webpack 打包后代码的异步调用,又是共用运行时,远程模块只是作为组件使用,在性能上损耗较少。配置 share 后,默认会将共用的依赖包单独打包,并通过异步 chunk 加载,如下图所示:

webpack5 针对 MF 提供了很多精细化的配置,这部分我们在以后的文章中进行讨论。

总结:应用场景

由于 qiankun 本身是基座和插槽的思想,适合用于存在一个中心应用的场景,例如后台管理系统,SAAS 系统。

MF 是去中心化部署应用集群的思想,比较适合多个相对独立的应用,但又需要互相调用对方核心能力的场景,例如 APP 内存在多个 H5 应用,这些 H5 在大多时候都是独立运行的,组成了 APP 内丰富的二级页面,但有时候又需要业务之间又需要互相调用对方的能力(例如某业务模块和订单模块独立部署,但业务有时候需要在页面中展示购买页面)

qiankun 由于是应用级别的加载,又由于沙箱的存在,其性能会有较大的损失,更适合在 PC 端拥有较好性能浏览器中使用。而 H5 的单个页面内容相对较少,对性能要求更高,因遵循“最小模块”加载的原则,不论从功能上还是性能上都不适合使用 qiankun,而作为模块加载 MF 相比之下可能会有更大的发挥空间。


微前端框架初探,对比qiankun和Module-Federation
https://www.wobushi.top/2021/微前端框架初探,对比qiankun和Module-Federation/
作者
Pride Su
发布于
2021年10月18日
许可协议