一、背景
为了解决单体应用在一个相对长的时间跨度下,由于参与的人员、团队的增多、变迁,从一个普通应用演变成一个巨石应用(Frontend Monolith)后,随之而来的应用不可维护的问题。使使用不同技术栈的应用之间没有任何直接或间接的技术栈、依赖、以及实现上的耦合而调研微前端的技术框架。
二、什么是微前端
微前端的概念是由ThoughtWorks在2016年提出的,它借鉴了微服务的架构理念,核心在于将一个庞大的前端应用拆分成多个独立灵活的小型应用,每个应用都可以独立开发、独立运行、独立部署,再将这些小型应用融合为一个完整的应用,或者将原本运行已久、没有关联的几个应用融合为一个应用。微前端既可以将多个项目融合为一,又可以减少项目之间的耦合,提升项目扩展性,相比一整块的前端仓库,微前端架构下的前端仓库倾向于更小更灵活。
它主要解决两个问题:
1、随着项目迭代应用越来越庞大,难以维护。
2、跨团队或跨部门协作开发项目导致效率低下的问题。
前端微服务化,是微服务架构在前端的实施,每个前端应用都是完全独立(技术栈、开发、部署、构建独立)、自主运行的,最后通过模块化的方式组合出完成的应用。
采用这种方式意味着,一个页面上可以同时存在两个以上的前端应用在运行。
微前端的核心价值:
- 技术栈无关 主框架不限制接入应用的技术栈,微应用具备完全自主权
- 独立开发、独立部署 微应用仓库独立,前后端可独立开发,部署完成后主框架自动完成同步更新
- 增量升级 在面对各种复杂场景时,我们通常很难对一个已经存在的系统做全量的技术栈升级或重构,而微前端是一种非常好的实施渐进式重构的手段和策略
- 独立运行时 每个微应用之间状态隔离,运行时状态不共享
在面对各种复杂场景时,我们通常很难对一个已经存在的系统做全量的技术栈升级或重构,而微前端是一种非常好的实施渐进式重构的手段和策略。
三、微前端框架选型
iframe框架
iframe框架优点
- 非常简单,使用没有任何心智负担
- 框架稳定,上手难度低
- web应用隔离的非常完美,无论是js、css、dom都完全隔离开来
- 多应用激活,页面上可以摆放多个iframe来组合业务
iframe框架缺点
- 路由状态丢失,刷新一下,iframe的url状态就丢失了,后退前进按钮无法使用。
- dom割裂严重,弹窗只能在iframe内部展示,无法覆盖全局(无法解决)
- web应用之间通信非常困难,复杂。全局上下文完全隔离,内存变量不共享。iframe 内外系统的通信、数据同步等需求,主应用的 cookie 要透传到根域名都不同的子应用中实现免登效果。(很难解决)
- 每次打开白屏时间太长,对于SPA 应用来说无法接受,性能比较低。每次子应用进入都是一次浏览器上下文重建、资源重新加载的过程。
使用iframe框架只适合做简单的页面渲染。无法解决的问题会给产品带来非常严重的体验问题。
single-spa 框架
single-spa是一个用于前端微服务化的JavaScript前端解决方案, 也是最早的微前端整合方案。
single-spa的原理简单的说就是,single-spa将子应用也看做一个spa的页面。主应用通过路由匹配的方式,加载并显示不同的子应用资源,子应用会经过下载(loaded)、初始化(initialized)、被挂载(mounted)、卸载(unmounted)和unloaded(被移除)等过程。single-spa会通过"生命周期"为这些过程提供钩子函数。
single-spa 的主要实现思路为:
- 预先注册子应用(激活路由、子应用资源、生命周期函数)
- 监听路由的变化,匹配到了激活的路由则加载子应用资源,顺序调用生命周期函数并最终渲染到容器
缺点:
- 太过基础,对原项目改造过多,使用成本高
QianKun
是一款由蚂蚁金服推出的比较成熟的微前端框架,基于 single-spa 的微前端实现库,用于将 Web 应用由单一的单体应用转变为多个小型前端应用聚合为一的应用。采用MIT开源协议。
特性:
-
基于 single-spa 封装,提供了更加开箱即用的 API。
-
技术栈无关,任意技术栈的应用均可 使用/接入,不论是 React/Vue/Angular/JQuery 还是其他等框架。
-
HTML Entry 接入方式,让你接入微应用像使用 iframe 一样简单。
-
样式隔离,确保微应用之间样式互相不干扰。
-
JS 沙箱,确保微应用之间 全局变量/事件 不冲突。
-
资源预加载,在浏览器空闲时间预加载未打开的微应用资源,加速微应用打开速度。
-
umi 插件,提供了 @umijs/plugin-qiankun 供 umi 应用一键切换成微前端架构系统。
qiankun微前端架构则进一步对single-spa进行完善,主要的完善点:
- 子应用资源由 js 列表修改进为一个url,大大减轻注册子应用的复杂度
- 实现应用隔离,完成js隔离方案 (window工厂) 和css隔离方案 (类vue的scoped)
- 增加资源预加载能力,预先子应用html、js、css资源缓存下来,加快子应用的打开速度
优点:
-
监听路由自动的加载、卸载当前路由对应的子应用
-
完备的沙箱方案,js沙箱做了SnapshotSandbox、LegacySandbox、ProxySandbox三套渐进增强方案,css沙箱做了两套strictStyleIsolation、experimentalStyleIsolation两套适用不同场景的方案
-
路由保持,浏览器刷新、前进、后退,都可以作用到子应用
-
应用间通信简单,全局注入
缺点:
-
基于路由匹配,无法同时激活多个子应用,也不支持子应用保活,升级后的版本支持同时激活多个微应用,且微应用之间相互不干扰
-
改造成本较大,从 webpack、代码、路由等等都要做一系列的适配
-
css 沙箱无法绝对的隔离,js 沙箱在某些场景下执行性能下降严重
-
无法支持 vite 等 ESM 脚本运行
MicroApp
MicroApp借鉴了WebComponent的思想,通过CustomElement结合自定义的ShadowDom,将微前端封装成一个类WebComponent组件,从而实现微前端的组件化渲染。采用MIT开源协议。
MicroApp优势:
-
使用简单 我们将所有功能都封装到一个类WebComponent组件中,从而实现在基座应用中嵌入一行代码即可渲染一个微前端应用。 同时micro-app还提供了js沙箱、样式隔离、元素隔离、预加载、数据通信、静态资源补全等一系列完善的功能。
-
零依赖 micro-app没有任何依赖,这赋予它小巧的体积和更高的扩展性。
-
兼容所有框架 为了保证各个业务之间独立开发、独立部署的能力,micro-app做了诸多兼容,在任何技术框架中都可以正常运行。目前有: react (version 16, 17) vue (version 2, 3) vite (version 2) angular (version 11) nextjs (version 11) nuxtjs (version 2)
以上框架可以任意组合,换句话说任何一个框架都可以作为基座嵌入其它类型的子应用,任何一个框架也可以作为子应用被其它框架嵌入,包括上面没有列举出的其它库,如 svelte、umi ...
缺点:
-
接入成本较 qiankun 有所降低,但是路由依然存在依赖(虚拟路由已解决);
-
多应用激活后无法保持各子应用的路由状态,刷新后全部丢失(虚拟路由已解决);
-
css 沙箱依然无法绝对的隔离,js 沙箱做全局变量查找缓存,性能有所优化;
-
支持 vite 运行,但必须使用 plugin 改造子应用,且 js 代码没办法做沙箱隔离;
-
对于不支持 webcompnent 的浏览器没有做降级处理;
-
PC端:除了IE浏览器,其它浏览器基本兼容。
-
移动端:ios10+、android5+
无界
无界微前端是一款基于 Web Components + iframe 微前端框架。采用MIT开源协议。
优点:
- 多应用同时激活在线 框架具备同时激活多应用,并保持这些应用路由同步的能力。
- 组件式的使用方式
无需注册,更无需路由适配,在组件内使用,跟随组件装载、卸载。无界提供基于 vue 封装的 wujie-vue 和基于 react 封装的 wujie-react,用户可以当初普通组件一样加载子应用
-
应用级别的 keep-alive 子应用开启保活模式后,应用发生切换时整个子应用的状态可以保存下来不丢失,结合预执行模式可以获得类似ssr的打开体验
-
纯净无污染
-
无界利用iframe和webcomponent来搭建天然的js隔离沙箱和css隔离沙箱
-
css隔离沙箱 无界将子应用的 dom 放置在 webcomponent + shadowdom 的容器中,除了可继承的 css 属性外实现了应用之间 css 的原生隔离
-
js隔离沙箱 无界将子应用的 js 放置在 iframe(js-iframe)中运行,实现了应用之间 window、document、location、history 的完全解耦和隔离。
-
利用iframe的history和主应用的history在同一个top-level browsing context来搭建天然的路由同步机制
-
副作用局限在沙箱内部,子应用切换无需任何清理工作,没有额外的切换成本。子应用不用担心污染问题。
-
性能和体积兼具 子应用执行性能和原生一致,子应用实例instance运行在iframe的window上下文中,避免with(proxyWindow){code}这样指定代码执行上下文导致的性能下降,但是多了实例化iframe的一次性的开销,可以通过 proload 提前实例化 体积比较轻量,借助iframe和webcomponent来实现沙箱,有效的减小了代码量
-
开箱即用 不管是样式的兼容、路由的处理、弹窗的处理、热更新的加载,子应用完成接入即可开箱即用无需额外处理,应用接入成本也极低
-
功能强大 支持子应用保活、子应用内嵌、多应用激活、去中心化通信、生命周期、插件系统、vite 框架支持、兼容 IE9 (有待考究,有用户评论在IE10,IE11上部分会存在问题)、应用共享。 不足:
-
内存占用较高,为了降低子应用的白屏时间,将未激活子应用的shadowRoot和iframe常驻内存并且保活模式下每张页面都需要独占一个wujie实例,内存开销较大
-
兼容性一般,目前用到了浏览器的shadowRoot和proxy能力,并且没有做降级方案
-
iframe劫持document到shadowRoot时,某些第三方库可能无法兼容导致穿透
总结
无界微前端采用 webcomponent + iframe 的来加载子应用,具有成本低、速度快、原生隔离、功能强大等一系列优点,在满足用户核心诉求的同时让使用微前端的体验就像使用普通组件一样简单,极大的降低了使用门槛。且已经开源。但使用人数不是很多。相比来说,乾坤使用的人数以及活跃度最高。
腾讯无界:github.com/Tencent/wuj...
阿里乾坤:github.com/umijs/qiank...
京东MicroApp:github.com/micro-zoe/m...
总结不好的地方请批评指正,谢谢😄