引子
对微前端方向有理解的同学可能都看过 qiankun 的文档,深刻的同学预计也去翻过其代码和 single-spa 的源码。一年前我也是受微前端思维的影响,过后刚好面临的业务是变动频繁,须要反对线上性能的热插拔和独立部署。充沛调研了微前端和 qiankun 之后,发现很适宜以后业务,才开始开始实际微前端的。因为 single-spa 太过于简陋,就采纳 qiankun@1.x 作为微前端驱动,明天想把这段时间以来遇到的问题和解决之道跟大家分享一下。
可能面临的业务场景
假如你当初保护或新开发这样一个我的项目,业务变动频繁,页面性能有反复,但格调是统一的,临时只有 pc 端。你拿到设计稿后发现,能够把业务分拆成多套 layout,由基座 (主利用) 提供。性能独立的模块集成在子利用,每个子利用有非凡的 routerBase。
咔咔咔,两三下你做完了所有工作,子利用也能在线配置,反对热插拔和独立部署。爽歪歪~
几天后忽然有了以下几个新业务场景,你陷入了深思。。。
场景一:随着业务的变动,须要反对挪动端。
你新建了个子利用,routerBase 设置为 h5。当判断是挪动端时主动跳转 /h5/xxx。如果 pc 端拜访 /h5/xxx 时,主动重定向到 /xxx,能勉强应酬该场景,不过因为基座太重导致挪动端渲染很慢,在挪动端应用“后退 / 后退”按钮也会因为重定向太多导致凌乱,有时候页面渲染成 pc 页面或无奈渲染。
场景二:页面是响应式的,挪动端点击登录后,也能共享登录态。
响应式页面是流动页,有流动报名,就要求登录态共享。当用户在挪动端点击登录时,理当跳转到挪动端的登录页面,登录完重定向到流动页面 须要是登录胜利的状态。如果是每个子利用都有 routerBase,来回跳转好几次,而且还要想方法共享登录。
场景三:老板要求 pc 端和挪动端 URL 统一。。。
routerBase 人造断绝了这种可能性,根本无法做到!
场景四:老板要求一个四年前的我的项目聚合到门户站点中。。。
该项目标很多依赖特地是脚手架都曾经重大过期,锁定一级依赖的版本但锁不了二级以上的版本,导致构建公布失败。根本无法往我的项目代码中退出 bootstrap/mount/unmount…!
qiankun 的“kun”(困)境
qiankun 的定位可能是中后盾我的项目的聚合。这类我的项目彼此间很少依赖,登录态的管制能够在基座中实现,属于一个基座下的多个串联。但面临上述场景时,就显得力不从心。
另外上述场景也裸露了 qiankun 的诸多问题:
- 基座个别由实在的业务利用承载,提供登录等性能,也提供多套 layout;
- 基座很容易耦合很多 pc 端的 UI 库和性能代码;
- 基座很容易沦为通用数据和逻辑的聚集地,尽管这些不是基座利用的职责;
- 重大依赖 routerBase,框架判断便当但就义了灵活性;
- 多实例共存反对有余,目前仅反对 microApp 模式,且这种利用不倡议有路由零碎;
- 重大依赖生命周期 bootstrap/mount/unmount;
破局之道
@icatjs/micro 是我这四个月来实现并在理论我的项目中实际的新一代微前端框架,岂但能轻松应酬上述“窘境”,还具备其余良好的个性。目前仅有两个办法 registerSubapps
和 start
,其余须要留神的就是子利用的配置了。TA 是如何应答上述窘境的呢?听我一一分享下:
端利用(或称 layout 利用)
大家看到这个新名词,不要认为对子利用做了强制的分类。只有某个子利用 a 提供了 layout 或一些门路被用作了 layout,又被其余子利用 b 依赖了,那么该利用 a 就可以看做是“端利用”。a 是不是端利用,本人基本不晓得,它会按子利用失常的加载。而 b 会在 a 提供了挂载点后再渲染到页面上。看个例子吧~
这是 端利用 的配置
{
"name": "a",
"entry": "aaa",
"history": "browser",
"props": {},
"rules": [
{
"rule": "/",
"container": "#mountNode",
"endType": "pc"
}
]
}
解析下:a 作为 pc 端的利用,门路规定配置的是通配符 /
,这样所有的路由都会被这个利用匹配到。当然会通过 endType
优先判断是哪个端,而后再去解决利用的“依赖链”。目前因为场景比较简单,每个路由下只反对一条依赖链。实践上讲可反对多条依赖链,也就是 多链多实例同时并存。
这是 子利用 的配置
{
"name": "b",
"entry": "bbb",
"history": "browser",
"props": {},
"rootVars": {
"externals": {
"@react": "React",
"@react-dom": "ReactDOM",
"userInfo": "userInfo"
}
},
"rules": [
{
"rule": "/b/activities/1520",
"layout": "a > /layout/headless",
"endType": "none"
},
{
"rule": "/b/tec-support",
"container": "#mountNode",
"endType": "none"
},
{
"rule": "/development",
"layout": "a > /layout/basic",
"endType": "pc"
}
]
}
也解析下:能够看 rules 中配置了三个典型的规定,第一条依赖了端利用 a 的 /layout/headless,第二条不依赖任何端利用,第三条依赖了 a 的 /layout/basic。
不配置 container 的门路,如果是子利用默认是 #subappMountNodeWrapper
,如果是端利用不依赖任何 layout 则默认是 #appMountNodeAndDoNotCover
。这样如果页面中有这些节点呈现时,子利用就会渲染到该节点上。
大家也能够看到,一个子利用的激活与否只和门路规定无关,这些规定恪守 single-spa 的 activeWhen 规定,能够是字符串、函数或数组。而每条门路规定都有本人的 container,也有属于本人的端 endType 和 layout。这样一个子利用既能够作为依赖链上的一个端利用,又能够作为独立的子利用。按门路规定灵便组合,适应多种场景须要。
留神!端利用也能够依赖其余端利用,只须要在其门路规定上配置须要依赖的门路即可。
entry
能够是一个 html 文件门路,也能够是一个数组,蕴含多个 js、css 和 html。初始化挂载点时,以最初一个 html 的内容填充进去。
全局路由零碎
内置解决了 react/vue 多个子利用同时被激活,多个路由零碎抵触的问题。无需再像应用 qiankun 那样,还要把子利用的路由配置到主利用中,以防抵触。全局路由会拦挡路由变动,把实在门路和 layout 门路散发到各个子利用,使其能失常渲染。
并且,所有子利用都能够有本人独立的 404 页面。能够把子利用齐全看成是独立的利用,无需顾虑路由的默认匹配,无需放心路由不匹配时间接进入利用的 404 页面。
沙箱
内置了 iframe 沙箱,子利用的代码运行是在 iframe 中。这样代码的状态都会保留在 iframe 中,不必麻烦提供快照,人造具备快照能力。也内置了垃圾回收队列,当一个子利用 5 分钟内不被激活,会被开释掉 iframe。
留神!这些 iframe 都是空白 iframe,消耗的渲染资源很少。但框架在 iframe 中提供了虚构 BOM,使这些字利用运行完的后果可能正确渲染到 iframe 外的实在渲染层中。
留神 2!子利用的所有对 dom 的操作都被限度在挂载点中,换言之,document.body 指向的是挂载点而不是渲染层的实在 body。这种紧密的管制也体现在 getElementById 等办法中。
当然还有其余一些个性如 第三方库共享 、 全局数据共享 、 组件 & 办法 & 状态流共享 和缓存机制 等,首次介绍就先不深刻了。后续会筹备官网,全面介绍这些个性的。
到此,咱们梳理一下窘境的解决之道:
- 场景一,须要反对挪动端。因为去掉了 routerBase 的依赖,又反对端利用,人造解决了基座重造成的渲染问题,重复重定向造成的跳转问题。
- 场景二,页面是响应式的须要共享登录态。因为反对 layout 依赖链,某个端利用能够集中处理登录逻辑,其余端利用依赖其提供的性能即可。逻辑能够通过流共享模式或者全局数据共享,散发到多个子利用。响应式的页面属于依赖链的某个节点,天然能及时取得登录态。
- 场景三,URL 一致性。因为去掉了 routerBase 的依赖,框架会在初始化时判断所处的终端,进而激活不同端利用。而端利用的门路规定都能够配置成通配符
/
,这样很容易保障 URL 统一。 - 场景四,四年前的老我的项目集成。框架反对无生命周期的我的项目,能够无缝渲染到门户站点中来。这是我测试的截图,大家有趣味能够看下:
这是集成的 2018 年的 seeconf 官网:
这是集成的口碑官网:
是否解决了 qiankun 的窘境呢?
因为通用逻辑和 layout 被摊派到一层层的“端利用”中,基座只须要做好对框架的援用和对规定的获取与解析,就能驱动起整体的站点运行起来。子利用的路由也不必顾虑抵触,而思考在主利用中 copy 一份。
基座能够做到很薄,每个端只需加载其须要的 UI 库或组件。比方 pc 端应用了 antd,挪动端能够应用 antd-mobile,框架不会把 antd 加载到挪动端去。
还有哪些有余?
- 不倡议基座具备路由零碎,目前还没去试验基座路由和子利用路由抵触的场景。
- 多路由零碎抵触计划,临时没有反对 angular,对 vue 的反对可能存在一点儿 bug。
- 多条依赖链场景暂未反对,目前只解决了第一条依赖链。
- 子利用中一些 js 灵便写法,如 eval 中的全局变量 var 去定义,包含自身的 var 定义的全局变量,还无奈正确挂载到虚构 window 上。可能存在某些我的项目加载报错的状况。
- 梳理了 21 种路由抵触的场景,可能存在例外的状况。
浏览器兼容
支流浏览器 chrome, safari, edge, firefox 等都兼容,国内小众浏览器 360、qq 浏览器等也兼容。优先应用 Proxy,不反对则进化为 Object.defineProperty。
谁在应用
目前平头哥 IoT 团队在做芯片凋谢社区(OCC),这个框架的诞生也是为了满足其一直变动的业务需要。大家能够看下 pc 端和挪动端的 URL 是雷同的,但激活的子利用是不同的。
也心愿看到本文的同学,在将来某个时刻应用 @icatjs/micro 框架,做出精彩纷呈的作品来!
应一些同学的反馈,顺手搞了个示例 https//github.com/icatjs/icatjs-micro-demo, 请大家初步理解下该框架的应用。