前言
MicroApp是一款基于类WebComponent进行渲染的微前端框架,不同于目前风行的开源框架,它从组件化的思维实现微前端,旨在升高上手难度、晋升工作效率。它是目前市面上接入微前端老本最低的框架,并且提供了JS沙箱、款式隔离、元素隔离、预加载、资源地址补全、插件零碎、数据通信等一系列欠缺的性能。MicroApp与技术栈无关,也不和业务绑定,能够用于任何前端框架和业务。
本篇文章中咱们会从业务背景、实现思路介绍MicroApp,也会具体介绍它的应用形式和技术原理。
业务背景
随着这些年互联网的飞速发展,很多企业的web利用在继续迭代中性能越来越简单,参加的人员、团队一直增多,导致我的项目呈现难以保护的问题,这种状况PC端尤其常见,许多研发团队也在找寻一种高效治理简单利用的计划,于是微前端被提及的越来越频繁。
微前端并不是一项新的技术,而是一种架构理念,它将繁多的web利用拆解成多个能够独立开发、独立运行、独立部署的小型利用,并将它们整合为一个利用。
在理论业务中,咱们也遇到同样的问题,并且在不同的业务场景下尝试了各种解决方案,如iframe、npm包、微前端框架,并对各种计划的优劣进行了比照。
iframe:在所有微前端计划中,iframe是最稳固的、上手难度最低的,但它有一些无奈解决的问题,例如性能低、通信简单、双滚动条、弹窗无奈全局笼罩,它的成长性不高,只适宜简略的页面渲染。
npm包:将子利用封装成npm包,通过组件的形式引入,在性能和兼容性上是最优的计划,但却有一个致命的问题就是版本更新,每次版本公布须要告诉接入方同步更新,治理十分艰难。
微前端框架:风行的微前端框架有single-spa和qiankun,它们将保护老本和性能上达到一种均衡,是目前实现微前端备受推崇的计划。
因为iframe和npm包存在问题实践上无奈解决,在最后咱们采纳qiankun作为解决方案,qiankun是在single-spa根底上进行了封装,提供了js沙箱、款式隔离、预加载等性能,并且与技术栈无关,能够兼容不同的框架。
业务诉求
qiankun尽管优良,但仍然无奈满足咱们的预期。第一个问题是在咱们理论应用场景中,每个接入微前端的我的项目运行已久,且每个我的项目由不同的人员和团队负责,如何升高对源代码的侵入性,缩小代码批改和沟通老本,这是咱们十分关怀的点,所以咱们须要一种比qiankun接入老本更小的计划。第二个问题是在多方利用接入的状况下,沙箱并不能完满躲避所有问题,但qiankun解决此类不可意料的问题的能力并不是十分高效。在不停的摸索中,咱们找到一种极致简洁的实现思路,它像应用组件一样简略,只批改一点点代码就能够接入微前端,并且还提供插件零碎,赋予开发者灵活处理问题的能力。
实现思路
微前端分为主利用和子利用,主利用也称为基座利用,是其它利用的容器载体,子利用则是被嵌入方。咱们别离从主利用和子利用的角度登程,探寻一种更简洁和无效的接入微前端的形式。
对于qinkun和single-spa的思考
在single-spa和qiankun中都是通过监听url change事件,在路由变动时匹配到渲染的子利用并进行渲染。这种基于路由监听渲染是single-spa最早实现的,作为呈现最早、最有影响力的微前端框架,single-spa被很多框架和公司借鉴,也导致目前实现的微前端的形式大多是基于路由监听。
同时single-spa要求子利用批改渲染逻辑并暴露出三个办法:bootstrap、mount、unmount,别离对应初始化、渲染和卸载,这也导致子利用须要对入口文件进行批改。这个特点也被qiankun继承下来,并且须要对webpack配置进行一些批改。
基于路由监听的实现形式和对子利用入口文件以及webpack配置的批改是必须的吗?
其实并不是,微前端的外围在于资源加载与渲染,iframe的渲染形式就是一个典型,只有可能实现一种元素隔离的性能并且路由符合要求,子利用实践上不须要批改代码就能够嵌入另外一个页面渲染,咱们试图从这个角度中找到不一样的实现思路。
微前端的组件化
要想简化微前端的实现步骤,必须摒弃旧的实现思路,摸索出不同的路线。
咱们借鉴了WebComponent的思维,以此为根底推出另一种更加组件化的实现形式:类WebComponent + HTML Entry。
HTML Entry:是指设置html作为资源入口,通过加载近程html,解析其DOM构造从而获取js、css等动态资源来实现微前端的渲染,这也是qiankun目前采纳的渲染计划。
WebComponent:web原生组件,它有两个外围组成部分:CustomElement和ShadowDom。CustomElement用于创立自定义标签,ShadowDom用于创立暗影DOM,暗影DOM具备人造的款式隔离和元素隔离属性。因为WebComponent是原生组件,它能够在任何框架中应用,实践上是实现微前端最优的计划。但WebComponent有一个无奈解决的问题 – ShadowDom的兼容性十分不好,一些前端框架在ShadowDom环境下无奈失常运行,尤其是react框架。
类WebComponent:就是应用CustomElement联合自定义的ShadowDom实现WebComponent基本一致的性能。
因为ShadowDom存在的问题,咱们采纳自定义的款式隔离和元素隔离实现ShadowDom相似的性能,而后将微前端利用封装在一个CustomElement中,从而模仿实现了一个类WebComponent组件,它的应用形式和兼容性与WebComponent统一,同时也避开了ShadowDom的问题。并且因为自定义ShadowDom的隔离个性,Micro App不须要像single-spa和qiankun一样要求子利用批改渲染逻辑并暴露出办法,也不须要批改webpack配置。
咱们通过上述计划封装了一个自定义标签micro-app
,它的渲染机制和性能与WebComponent相似,开发者能够像应用web组件一样接入微前端。它能够兼容任何框架,在应用形式和数据通信上也更加组件化,这显著升高了基座利用的接入老本,并且因为元素隔离的属性,子利用的改变量也大大降低。
应用形式
接下来咱们将别离介绍主利用和子利用的接入形式。
以react代码举例
主利用
每个自定义标签micro-app
渲染后就是一个微前端的子利用,它的应用形式相似于iframe标签。
咱们须要给标签传递三个根底属性:
- name:名称
- url:子利用页面地址
- baseurl:baseurl是基座利用调配给子利用的路由前缀
应用形式如下:
子利用
如果子利用只有一个页面,没有路由配置,则不须要做任何批改。
如果子利用是多页面,只须要批改路由配置,增加路由前缀。
如下:
window.__MICRO_APP_BASE_URL__是由基座利用下发的路由前缀,在非微前端环境下,这个值为undefined
实现以上配置即可实现微前端的渲染,对源码的改变量很少。当然MicroApp还提供了其它一些能力,如插件零碎、数据通信,咱们接下来做具体介绍。
外围原理
MicroApp 的外围性能在CustomElement根底上进行构建,CustomElement用于创立自定义标签,并提供了元素的渲染、卸载、属性批改等钩子函数,咱们通过钩子函数获知微利用的渲染机会,并将自定义标签作为容器,微利用的所有元素和款式作用域都无奈逃离容器边界,从而造成一个关闭的环境。
概念图
渲染流程
通过自定义元素micro-app
的生命周期函数connectedCallback
监听元素被渲染,加载子利用的html并转换为DOM构造,递归查问所有js和css等动态资源并加载,设置元素隔离,拦挡所有动态创建的script、link等标签,提取标签内容。将加载的js通过插件零碎解决后放入沙箱中运行,对css资源进行款式隔离,最初将格式化后的元素放入micro-app
中,最终将micro-app
元素渲染为一个微前端的子利用。在渲染的过程中,会执行开发者绑定的生命周期函数,用于进一步操作。
流程图
元素隔离
元素隔离源于ShadowDom的概念,即ShadowDom中的元素能够和内部的元素反复但不会抵触,ShadowDom只能对本人外部的元素进行操作。
MicroApp模仿实现了相似的性能,咱们拦挡了底层原型链上元素的办法,保障子利用只能对本人外部的元素进行操作,每个子利用都有本人的元素作用域。
元素隔离能够无效的避免子利用对基座利用和其它子利用元素的误操作,常见的场景是多个利用的根元素都应用雷同的id,元素隔离能够保障子利用的渲染框架可能正确找到本人的根元素。
概念图
实际效果
如上图所示,micro-app
元素外部渲染的就是一个子利用,它还有两个自定义元素 micro-app-head
、micro-app-body
,这两个元素的作用别离对应html中的head和body元素。子利用在原head元素中的内容和一些动态创建并插入head的link、script元素都会挪动到micro-app-head
中,在原body元素中的内容和一些动态创建并插入body的元素都会挪动到micro-app-body
中。这样能够避免子利用的元素透露到全局,在进行元素查问、删除等操作时,只须要在micro-app
外部进行解决,是实现元素隔离的重要根底。
能够将micro-app
了解为一个内嵌的html页面,它的构造和性能都和html页面相似。
插件零碎
微前端的应用场景非常复杂,即使有沙箱机制也无奈防止所有的问题,所以咱们提供了一套插件零碎用于解决一些无奈预知的问题。
插件能够了解为合乎特定规定的对象,对象中提供一个函数用于对资源进行解决,插件通常由开发者自定义。
插件零碎的作用是对传入的动态资源进行初步解决,并顺次调用符合条件的插件,将初步解决后的动态资源作为参数传入插件,由插件对资源内容进一步的批改,并将批改后的内容返回。插件零碎赋予开发者灵活处理动态资源的能力,对有问题的资源文件进行批改。
插件零碎自身是污浊的,不会对资源内容造成影响,它的作用是兼顾各个插件如何执行,当开发者没有设置插件时,则传入和传出的内容是统一的。
js沙箱和款式隔离
js沙箱通过Proxy代理子利用的全局对象,避免利用之间全局变量的抵触,记录或清空子利用的全局副作用函数,也能够向子利用注入全局变量用于定制化解决。
款式隔离是指对子利用的link和style元素的css内容进行格式化解决,确保子利用的款式只作用域本身,无奈影响内部。
MicroApp借鉴了qiankun的js沙箱和款式隔离计划,这也是目前利用宽泛且成熟的计划。
预加载
MicroApp 提供了预加载子利用的性能,它是基于requestIdleCallback实现的,预加载不会对基座利用和其它子利用的渲染速度造成影响,它会在浏览器闲暇工夫加载利用的动态资源,在利用真正被渲染时间接从缓存中获取资源并渲染。
资源地址补全
微前端中经常出现资源失落的景象,起因是基座利用将子利用的资源加载到本人的页面渲染,如果子利用的动态资源地址是绝对地址,浏览器会以基座利用所在域名地址补全动态资源,从而导致资源失落。
资源地址补全就是将子利用动态资源的绝对地址补全为相对地址,保障地址指向正确的资源门路,这种操作相似于webpack在运行时设置publicPath。
生命周期
在微利用渲染时,micro-app
元素在不同渲染阶段会触发相应的生命周期事件,基座利用能够通过监听事件来进行相应的操作。
生命周期列表:
- created:当micro-app标签被创立后,加载资源之前执行。
- beforemount:资源加载实现,正式渲染之前执行。
- mounted:子利用曾经渲染实现后执行
- unmount:子利用卸载时执行。
- error:当呈现破坏性谬误,无奈持续渲染时执行。
在卸载时,子利用也会接管到一个卸载的事件,用于执行卸载相干操作。
数据通信
数据通信是微前端中十分重要的性能,实现数据通信的技术计划很多,优良的计划能够晋升开发效率,缩小试错老本。咱们也钻研了qiankun等微前端框架数据通信的形式,但他们的实现形式并不适宜咱们,咱们尝试间接通过元素属性传递简单数据的模式实现数据通信。
对于前端研发人员最相熟的是组件化的数据交互的形式,而自定义元素micro-app作为类WebComponent,通过组件属性进行数据交互必然是最优的形式。但MicroApp在数据通信中遇到的最大的问题是自定义元素无奈反对设置对象类型属性,例如<micro-app data={x: 1}></micro-app>
会转换为 <micro-app data='[object Object]'></micro-app>
,想要以组件化模式进行数据通信必须让元素反对对象属性。
为了解决这个问题,咱们重写了micro-app
元素原型链上属性设置的办法,在micro-app
元素设置对象属性时将传递的值保留到数据中心,通过数据中心将值分发给子利用。
MicroApp中数据是绑定通信的,即每个micro-app
元素只能与本人指向的子利用进行通信,这样每个利用都有着清晰的数据链,能够防止数据的凌乱,同时MicroApp也反对全局通信,以便跨利用传递数据。
数据通信概念图
框架比照
为了更直观的感触Micro App和其它框架的区别,咱们应用一张图进行比照。
从比照图能够看出,目前开源的微前端框架中有的性能 MicroApp都有,并提供了一些它们不具备的性能,比方动态资源地址补全,元素隔离,插件零碎等。
业务实际
MicroApp曾经在公司外部多个我的项目中应用,体现良好,尤其是将一些老我的项目革新成微前端,在我的项目不受影响的状况下,即升高接入老本,又能够保障我的项目安稳运行,减小耦合。
为什么开源?
当初咱们团队打算应用微前端时,调研了市面上实现微前端的框架,可供选择的只有sigle-spa和qiankun。single-spa太过于根底,对原有我的项目的革新过多,老本太高。剩下的只有qiankun,但因为接入很多老我的项目,在理论应用中出了很多问题,咱们不得不对qiankun的源码进行大量的魔改。在此过程中,咱们对微前端的实现形式产生了一些本人的想法,并将这些想法付诸实践,于是有了MicroApp。
目前像qiankun相似提供欠缺性能的微前端框架太少了,当接入qiankun失败时,没有其余计划可供选择,这是咱们当初经验过的痛。所以咱们抉择将MicroApp开源,一是因为MicroApp有诸多翻新点,能够更简略的接入微前端,性能更加丰盛,二是能够让大家多一种抉择,没有完满的微前端框架,只有抉择多了,才晓得哪一个更适宜本人。
如果你对这个我的项目感兴趣,能够通过退出组织或提pull requests的形式参加共建,十分欢送与期待你的退出。
导航
GitHub地址:https://github.com/micro-zoe/…
官网地址:https://cangdu.org/micro-app
特地鸣谢:qiankun
发表回复