大家好,我叫Echa哥。
微前端已经是一个非常成熟的领域了,但开发者不管采用哪个现有方案,在适配成本、样式隔离、运行性能、页面白屏、子应用通信、子应用保活、多应用激活、vite 框架支持、应用共享等用户核心诉求都或存在问题,或无法提供支持。本文提供一种基于 iframe 的全新的微前端方案,完善地解决了这些核心诉求。
为什么还要造微前端框架
目前较成熟的微前方案有 qiankun、micro-App、EMP 方案,下面分别分析这三个微前端方案:
qiankun 方案
qiankun 方案是基于 single-spa 的微前端方案。
特点
不足
micro-app 是基于 webcomponent + qiankun sandbox 的微前端方案。
特点
不足
EMP 方案是基于 webpack 5 module federation 的微前端方案。
特点
不足
qiankun 方案对 single-spa 微前端方案做了较大的提升同时也遗留下来了不少问题长时间没有解决;
micro-app 方案对 qiankun 方案做了较多提升但基于 qiankun 的沙箱也相应会继承其存在的问题;
EMP 方案基于 webpack 5 联邦编译则约束了其使用范围;
目前的微前端方案在用户的核心诉求上都没有很好的满足,有很大的优化提升空间。
无界方案
无界微前端方案基于 webcomponent 容器 + iframe 沙箱,能够完善地解决适配成本、样式隔离、运行性能、页面白屏、子应用通信、子应用保活、多应用激活、vite 框架支持、应用共享等用户的核心诉求。
文档地址,demo 地址:https://wujie-micro.Github.io/demo-mAIn-vue/home,git 地址:https://github.com/Tencent/wujie
下面就成本、速度、隔离、功能等多个方面进行阐述。
成本低
无界微前端的成本非常低,主要体现在主应用的使用成本、子应用的适配成本两个方面。
主应用使用成本
主应用使用无界不需要学习额外的知识,无界提供基于 vue 封装的 wujie-vue 和基于 react 封装的 wujie-react,用户可以当初普通组件一样加载子应用,以 wujie-vue 举例:
子应用加载和普通 vue 组件加载并无二致,所有配置都收敛到组件的属性上。
子应用适配成本
子应用首先需要做支持跨域请求改造,这个是所有微前端框架运行的前提,除此之外子应用可以不做任何改造就可以在无界框架中运行,不过此时运行的方式是重建模式。
子应用在无界中会根据是否保活、是否做了生命周期适配进入不同的运行模式:
其中保活模式、单例模式、重建模式适用于不同的业务场景,就算复杂点的单例模式用户也只是需要做一点简单的生命周期改造工作,可以说子应用适配成本极低。
速度快
无界微前端非常快,主要体现在首屏打开快、运行速度快两个方面。
首屏打开快
目前大部分微前端只能做到静态资源预加载,但是就算子应用所有资源都预加载完毕,等到子应用打开时页面仍然有不短的白屏时间,这部分白屏时间主要是子应用 js 的解析和执行。
无界微前端不仅能够做到静态资源的预加载,还可以做到子应用的预执行。
预执行会阻塞主应用的执行线程,所以无界提供 fiber 执行模式,采取类似 react fiber 的方式间断执行 js,每个 js 文件的执行都包裹在 requestidlecallback 中,每执行一个 js 可以返回响应外部的输入,但是这个颗粒度是 js 文件,如果子应用单个 js 文件过大,可以通过拆包的方式降低体积达到 fiber 执行模式效益最大化。
运行速度快
子应用的 js 在 iframe 内运行,由于 iframe 是一个天然的 js 运行沙箱,所以无需采用 with (fakewindow) 这种方式来指定子应用的执行上下文,从而避免由于采用 with 语句执行子应用代码而导致的性能下降,整体的运行性能和原生性能差别不大。
原生隔离
无界微前端实现了 css 沙箱和 js 沙箱的原生隔离,子应用不用担心污染问题。
css 沙箱隔离
无界将子应用的 dom 放置在 webcomponent + shadowdom 的容器中,除了可继承的 css 属性外实现了应用之间 css 的原生隔离。
js 沙箱隔离
无界将子应用的 js 放置在 iframe(js-iframe)中运行,实现了应用之间 window、document、location、history 的完全解耦和隔离。
js 沙箱和 css 沙箱连接
无界在底层采用 proxy + Object.defineproperty 的方式将 js-iframe 中对 dom 操作劫持代理到 webcomponent shadowroot 容器中,开发者无感知也无需关心。
功能强大
无界微前端的功能非常强大,支持子应用保活、子应用内嵌、多应用激活、去中心化通信、生命周期、插件系统、vite 框架支持、兼容 IE9、应用共享。
子应用保活
当子应用设置为保活模式,切换子应用后仍然可以保持子应用的状态和路由不会丢失。
子应用嵌套
无界支持子应用多层嵌套,嵌套的应用和正常应用一致,支持预加载、保活、同步、通信等能力,需要注意的是内嵌的子应用 name 也需要保持唯一性,否则将复用之前渲染出来的应用
多应用激活
无界支持一个页面同时激活多个子应用并且保持这些子应用路由同步的能力。
去中心化通信
无界提供多种通信方式:window.parent 直接通信、props 数据注入、去中心化 EventBus 通信机制:
生命周期
无界提供完善的生命周期钩子供主应用调用:
无界提供强大的插件系统,方便用户在运行时去修改子应用代码从而避免将适配代码硬编码到仓库中。
无界插件主要能力如下:
无界子应用运行在 iframe 中原生支持 esm 的脚本,而且不用担心子应用运行的上下文问题,因为子应用读取的就是 iframe 的 window 上下文,所以无界微前端原生支持 vite 框架。
兼容 IE9
由于无界采用了 webcomponent + shadowdom + proxy 的方案,在某些低版本浏览器上无法运行时,无界微前端会自动降级。
降级方案采用:
自动降级后无界依然可以保证子应用的 css 和 js 原生隔离,但是由于 dom-iframe 的限制,弹窗将只能在子应用内部打开
应用共享
一个微前端系统可能同时运行多个子应用,不同子应用之间可能存在相同的包依赖,那么这个依赖就会在不同子应用中重复打包、重复执行造成性能和内存的浪费。
无界提供一种工程上的策略结合无界的插件能力,可以有效的解决这个问题(其他微前端框架也可以做到),这里以一个场景举例:主应用使用到了 ant-design-vue,子应用 A 也使用到了相同版本的 ant-design-vue。
主应用:
1、修改主应用的 index.js,将共享包挂载到主应用的 window 对象上
// index.jsimport Antdv from "ant-design-vue";// 将需要共享的包挂载到主应用全局window.Antdv = Antdv;
2、加载子应用时注入插件,将主应用的 Antdv 赋值到子应用的 window 对象上
子应用: webpack 设置 externals
module.exports = {externals: {"ant-design-vue": {root: "Antdv",commonjs: "Antdv",commonjs2: "Antdv",amd: "Antdv",},},
如果子应用需要单独运行可以参考文档
总结
无界微前端采用 webcomponent + iframe 的来加载子应用,具有成本低、速度快、原生隔离、功能强大等一系列优点,在满足用户核心诉求的同时让使用微前端的体验就像使用普通组件一样简单,极大的降低了使用门槛。
无界已经开源 ,欢迎 star ⭐️⭐️⭐️:https://github.com/Tencent/wujie