我正在参加「掘金·启航计划」
intro
关于项目的思考
方案确定
今年7月是刚好是入职大厂的第一年,上半年做了一个对我来说还蛮有挑战的项目。
项目大致的背景是这样:我所在的业务需要将自己的主页面中的一小部分业务隔离出来交给其他部门的同事维护,相当于我们自己的业务是父级,隔离出的业务是子级。
对于这个需求的做法,我脑子里就两种做法:
- 让别的部门的同事直接clone我们的仓库代码进行修改(×)
- 父级创造一个沙箱环境提供给子级(✅)
第一种方案无脑pass,如果需求着急可以用来过渡,但是这肯定不是一个长久之计。那就直接考虑第二种解决方案,对于前端来说,提到沙箱环境最简单的做法就是iframe了。
iframe的优点:
- 简单。父级在DOM里插入标签即可创造一个沙箱环境。
- 完全隔离。JS_CSS_HTML都与父级完全隔离,对父级无任何副作用。
- 多应用组合。同一个页面下可以配置不同src地址的iframe,实现多种业务和应用的组合。
iframe的缺点:
- 双边通信复杂且繁琐。不论是父级与子级还是子级与子级之间通信需要依靠postmessage去进行通信,并且通信时需要对应上响应通信的iframe窗口。
- 白屏时间长。因为iframe的状态是依赖父级应用的,只要父级刷新iframe的就丢失url状态进行重新加载,加载时进行一些通信的话,会导致子级部分的白屏时间比父级长很多。
- 子级可实现的功能受限。水能载舟亦能覆舟说的就是iframe的第2 个优点了,在某些场景下也算是个缺点:比如iframe的样式有可能会受父级样式影响导致子级页面出现滚动条等错误UI视图,并且弹窗只能在iframe的内部显示,无法像父级弹窗一样覆盖全局。子应用的事件操作不会冒泡到父级。
- 没有路由状态。子应用不能进行页面的前进和后退,并且父页面刷新会使得子应用的路由状态全部丢失,完全从头开始。
方案分析
iframe有这么多缺点,是不是不能用呢?当然是具体问题具体分析,对我此次的项目来说iframe是完美的解决方案。
下面是我自己的分析:
-
首先是缺点的第3和4点,对于子应用需要实现比较复杂的业务时,这个两点确实很致命,但是针对此次我的项目来说子应用不需要路由状态,也暂时不会有覆盖全局的样式要求。
-
然后再说第1点,iframe的两边通信确实有点复杂,但是好在我本次业务两边不需要太多的通信,只需要在父级加载的初始传递一些数据给子级,子级甚至不需要传递数据给父级,所以这一点对我来说暂时没有太大的影响。不过,为了减轻双边通信的繁琐程度,我们还是需要双方制定一些合适的通信协议来约束双方通信的方式,不然联调的时候非常非常麻烦。
-
最后是第2点,这个白屏时间就是一件有影响的事了。父页面已经加载好了,但是子应用那一块还是白屏的的话对用户的体验感就很差了,用户会看到页面有明显的闪动感。
那要放弃iframe的方案吗?当然不是,因为iframe的优点完完全全是我想要的,所以最终我考虑的是方案是:在父级已经初始化好而子级还没加载出来的这个时间段,子应用展示一个loading的页面UI,在加载成功之后替换。
具体做法:
在父级创建iframe沙箱环境时告知子级父级已经加载成功,此时子级就在沙箱环境展示loading态,等到子级的页面渲染成功之后替换掉loading态。对于用户而言,是有心里预期这部分是正在加载中的东西而不是很突兀的白屏闪动感。
困惑
至此,方案大体的方向就定下来了。项目最终的效果也是按照预期发展的。但是这不是我本篇文章要说的重点,重点是有一个故事是这样的:
当我做完整个项目,我并不觉得我的项目在前端界属于微前端方面。偶然一次和一位大佬讨论相关的东西,他有不同的看法,他觉得这是属于微前端的部分,觉得还可以做得更通用一些,还问了我对微前端是怎么理解的。我当时还是比较哑口无言的,下来之后就去查阅了相关的知识。
其实对于我自己来说,我试用了一些微前端的库之后,让我对微前端更困惑了。2019年在外网关于微前端有过特别大的一次争论,具体发生的事可以看这篇文章,我困惑的点和这篇文章一些观点不谋而合。
- 微前端概念是不是伪概念?
- 微前端的框架到底想要实现什么目标?
- 要不要使用这些框架?
- 使用哪一个框架?
- .....
我真的太多困惑了。
关于微前端思考
首先介绍一下概念,发现微前端的概念就是拿来主义,来源于后端。
概念
首先,微前端这个词语来源于微服务。谷歌云对微服务的定义是:微服务架构(通常简称为微服务)是指开发应用所用的一种架构形式。通过微服务,可将大型应用分解成多个独立的组件,其中每个组件都有各自的责任领域。在处理一个用户请求时,基于微服务的应用可能会调用许多内部微服务来共同生成其响应。
随着前端单页面应用(SPA)的盛行,一个单页面应用的迭代随着时间的推移也非常有可能变成大型的应用,因此前端也需要像服务端一样将这个大型的应用分解成多个独立的部分,那么这种形式就命名为微前端。
那其实简单来说,微前端技术方向就是为了解决一个问题:当一个页面需要拆分维护的时候,我们要用什么方案去解决。
微前端的概念是2016年底提出来的,到今年也发展了7年之久,市面有很多比较成熟的解决方案。 比如我前面所说的iframe的方案,也是一种解决方案,但是iframe的缺点也是比较明显的,不解决的话是没有办法称作为一个通用的技术方案。
核心点
我看了国内一些开源微前端技术的大厂对微前端解决问题树立的核心点主要有以下三个:
- 技术栈无关:完全隔离HTML/CSS/JS的沙箱环境。
- 父应用和子应用、子应用和子应用之间的状态管理以及通信方式。
- 运行性能和符合SPA的要求(比如白屏时间等),并且改造的成本不要花费巨大。
实现了上述核心点的话,那么我们可以利用微前端技术来将一个主应用作为控制台,每个子应用就像热插拔的插件系统一样去更新迭代,不需要的直接舍弃,老的子应用哪怕用的jQuery也不影响新的子应用去用TypeScript。
关于微前端开源方案
关于微前端的讨论,外网还爆发过一次剧烈的讨论,就是这玩意儿到底该不该用。 所以我自己在学习和了解这些技术的时候,会有意识的考虑和实际项目的契合度,
single-spa
single-spa是为了解决前端的JavaScript框架更新快同时死得也快的问题,比如最开始的jQuery,以及后面的Angular再到React和Vue。如果项目的周期真的有这么长的话,那么使用single-spa方案可以使得你在同一个页面使用不同的JavaScript框架,这样子的话 新功能使用新框架,旧的单页应用不用重写就可以共存。
这个是最早出现的一种微前端的解决方式,虽然不太完善,比如缺少CSS隔离等问题,需要后期自行去处理,但是算是提供了一个基础的思路,后续有一些方案是基于single-spa然后优化了这个方案的缺点,做到了真正的开箱即用。
qiankun
qiankun是一个基于single-spa的微前端实现库。通过一些技术补齐了single-spa的缺点,比如CSS隔离不完全等。具体的介绍大家可以看官网。
做了个demo体验了一下,发现了一些问题:
- qiankun主要是靠路由去做多应用的控制,1.0版本甚至不能在同一个页面下进行子应用嵌套,也就是说没有办法实现我的项目所要达到的目的。到现在的2.0版本可以通过一些配置去做嵌套,但是因为路由的原因还是会出一些小状况。
- 对子应用的侵入性太高,在最简单的demo情况下都需要子应用去配合配置,导致可插拔性不高。说回我自己的项目,既然把小部分业务交接出去给别人,那其实最想实现的就是工程上没有任何关联,大家各做各的,所以这一点对我来说也不太友好。
虽然qiankun看起来已经很🐂了,但是我自己感受来说觉得这个框架应用的场景还不是很清晰。 如果通过路由来做控制的话,其实后端也可以做,用Nginx配置一下不同路由加载不一样的资源,看起来也能解决大方向的问题了,并且是可以实现两个页面完全隔离。
🤔这里我有点困惑。有没有大佬来解析一下。
无界
无界微前端方案技术是基于 WebComponent 容器 + iframe 沙箱来实现的。
能够完善的解决适配成本、样式隔离、运行性能、页面白屏、子应用通信、子应用保活、多应用激活、vite 框架支持、应用共享等
👆🏻是从官网介绍摘抄过来的,我看了页面白屏、子应用保活和子应用通信的词语,看起来是把iframe的缺点都搞定了。因为是iframe的话,子应用嵌套肯定是没问题的。
做了个demo体验了一下:
我自己的项目目前还不能保活,无界实现了保活模式下的子应用不需要做改造,那必然是最好的。
这个是目前demo体验感最好的,至少套用到我自己的项目上是没有任何问题的。
但是不知道实际生产环境下是什么情况,这个github的star数和qiankun还是有区别的。后续打算研究一下源码,看看是怎么解决iframe的各个缺点的。
最后
我自己就找到这个在微前端看起来比较好的技术方案。之前外网关于微前端的争论,这篇文章写的来龙去脉,最终得出的结论就是用不用微前端取决于工程上的权衡,有好也有坏。
在我看来,其实在微前端概念没有出的时候,当项目逐渐堆叠的时候,我们也是会通过一些手段做拆分,但是如果都是一个团队去维护项目,怎么拆其实都可以。但是出现需要多个团队去维护的时候,这个时候拆分就是一个不太好解决的问题了。
还是不能盲目的一头扎进去,乱用带来的后果就是:
好好思考之后再用的话,就是这样: