共计 5384 个字符,预计需要花费 14 分钟才能阅读完成。
Module Federation: 是模块联邦的意思,在 webpack 5 中流行起来的,也属于一种微前端计划。
一、背景
1、客服高频工作场景
一线客服: 基于一站式工作台中的在线工作台及电话工作台,依据用户进线反馈的问题,查看以后用户相干的工单详情或订单详情,并依据理论状况决定是否创立新的工单。
二线客服: 依据各种渠道反馈的工单(其中 一个次要起源是一线客服的反馈),依据工单内容,分割用户或其余相干方沟通解决并完结工单。
2、应用 iframe 的背景
在上述场景中咱们能够晓得:
- 一线客服和二线客服不是同一批同学,分属不同的部门;
- 因为业务上的一些区别,所以 IM 与工单是两个不同的前端我的项目,也由不同的前端同学开发和保护;
- 即便应用微前端拆分后,IM、电话和工单也属于不同的微利用,工单页面在 IM 和电话子利用中没法间接引入工单详情页面
在 革新之前 IM 和电话工作台中应用到的工单 详情 页面都是应用 iframe 嵌套的,这在后期是最简便,兼容性最好的计划。
二、存在的问题
1、iframe 问题的扩大化
咱们晓得,单个 iframe 是比拟占 内存 的,关上比较慢,只是偶然应用的时候,这些可能并不是什么大问题,但在一线客服中有这么些场景会急剧扩充这些问题,具体如下:
- 一线客服与单个用户对话过程中,关上多个该用户的工单详情或订单详情
- 一线客服对接多个用户征询
- 一线客服频繁且疾速的切换不同的用户及不同的工单 / 订单详情
- 因为客服对切换不同会话的响应有要求,IM 侧对不同的会话页面做了缓存(如 keep-alive)
这会 导致 内存 耗费急剧升高,切换响应速度慢,甚至会导致浏览器解体,客服应用 体验 差,最终导致客服效力的升高 。
2、内存一直升高
模仿用户在 IM 中关上一个新客户的音讯,点击创立工单,点击工单详情,再关上一个新的客户音讯反复上述动作的页面文档数,内存占用及页面节点数的趋势图,如下:
因为页面缓存的存在,可见 内存 占用是越来越高的,在一分多钟的工夫内从 100 多 MB 到 500 多 MB,而且能够判断的是当用户的这类操作,其内存占有率将继续走高,尽管在大多数状况下浏览器的垃圾回收机制会启动,但因为:
- 页面级的缓存使垃圾回收不那么无效
- 在客服的长时的工作下,内存还是会继续走高
最终利用会越来越慢,甚至导致解体,并曾经有一些客服在反馈解体的问题了:
3、响应速度慢
先看段工单详情关上的视频,如下:
视频中打动工单详情并非首屏关上,也须要 2.8 秒,当首屏关上的时候甚至须要 7s!
留神: 此处及后续的数据都是在测试环境采集的,因为是外部实现的新开标签页,对 LCP(Largest Contentful Paint, 最大内容渲染), TTI(Time to Interactive, 可交互工夫)等不能很好采集,次要是依据谷歌性能工具中截屏中的工夫数据来获取的,该值更靠近于 TTI。
三、选型及对应策略
依据当下的状况,曾经不能再持续应用 iframe 了,那有什么计划能够满足咱们目前的情景呢,首先梳理咱们目前的诉求,这个诉求次要有两方面:
- 一方面当然是解决上述问题,晋升性能,晋升客服应用体验
- 另一方面它须要对前端来说要足够敌对,能实现,有良好兼容性,也要放弃前端的目前低成本保护
摆在咱们背后的罕用的计划大略有这么两个,npm 包和以 qiankun 为代表的微前端
计划 | 性能 | 保护 |
---|---|---|
npm | 好,与本地组件无异,性能是最好的 | 差,一旦工单有公布,IM 也得追随发版,不可承受 |
微前端 | 较好 | 好,我的项目解耦,IM 侧无需关怀工单侧的迭代及具体技术 |
1、npm 包适宜么
先看下咱们须要援用的页面自身,如下图所示:
它是一个 复杂度高的,业务关联性高,更新频次高的三高页面级组件,齐全不适宜做成低频的 npm 包了
2、微前端适合么
大家可能认为我要选 qiankun 为主的微前端计划了,但并不是,因为 qiankun 或其余相似的微前端计划在咱们这样的具体场景下也有一些问题:
2.1、对嵌套场景的反对度不高
在咱们一站式工作台的整体计划中,曾经应用 qiankun 将工单、IM、电话拆成了三个子利用,如果 IM 再援用工单子利用就会造成利用之间的嵌套,如下图所示:
搜查微前端嵌套计划:
- 社区没有官网反对嵌套计划:qiankun 微前端实际总结(二) – 掘金 这篇文章这段论述了嵌套的计划,能够看出尽管官网没有举荐计划,然而社区曾经有相干实际,然而反对度不够好,而且这些实际是基于在 webpack 构建根底上的;
- qiankun 对 vite 不敌对:见 issue 想问一下,将来是否思考反对 vite · Issue #1257 · umijs/qiankun,只是最近才缓缓的减少了对 vite 的反对。
论断 : 无论是 webpack 还是 vite,以沙箱隔离为次要解决方案的微前端在嵌套场景上 反对度不高 , 并且如果当前呈现更多,更深,甚至循环嵌套的状况的话,那就更辣手了。
2.2、场景不适宜
以沙箱隔离的微前端计划,还是会在每次援用时将我的项目自身初始化所需的文件都援用并且解析加载,即便你援用一个小组件他也会这么做,还是会影响组件加载的速度。所以它次要是解决 以我的项目维度的援用,隔离及性能问题。在以模块或组件为维度的情景不适宜,它还是有点重了。
那么是否存在这样一个计划,能够像 npm 包这样乖巧,只加载对应的组件代码,又能够像微前端这样间接援用,与我的项目无关呢,答案是有的,那就是这次的配角——Module Federation(模块联邦)。
四、Module Federation 模块联邦
模块联邦,它首先是在 webpack 5 中风行开来的,可见文档:Module Federation | webpack 中文文档,而且它也属于一种微前端计划。
1、咱们关注下它能干什么
我感觉一句话概括就是:它能容许一个线上部署的我的项目在运行时加载其余线上部署我的项目中的组件。
其中要害几点如下:
- 它没有沙箱隔离计划,与宿主环境共用一个 window 环境
- 加载时只加载指标组件及其相干的内容
- 无需扭转组件或页面在之前的我的项目目录地位或构造,间接依据对应目录层级援用即可
- 应用时与本我的项目组件应用形式统一,因为它就是一个组件,只是近程加载而已
2、基本原理
构想一下,在 webpack 中能够将一些后续加载的模块打成 chunk 包,而后在应用到这个模块的时候再懒加载,这种情景个别是在同一个我的项目中进行。
那么咱们是否也能够在 A 我的项目中把一个组件及其的依赖打包成 chunk 包,而在 B 我的项目中按约定的地址异步 import 方才那个 A 我的项目的 chunk 包,并运行应用呢?答案就是 Module Federation。
2.1、一些概念
- 近程组件提供方称为 remote 端,近程组件应用方称为 host 端。
- 一个我的项目既能够为 remote 端,也能够为 host 端,能够应用数个不同其余我的项目的组件,也能够为数个其余我的项目提供不同的组件。
据此,咱们甚至能够打造一个去中心化的利用集群,大略这样:
2.2、社区利用
而且此项技术已在多个出名厂商中利用:
- 摸索 webpack5 新个性 Module federation 在腾讯文档的利用 – 掘金(腾讯)
- 最全汇总之微前端常识和实战(EMP 技术计划) – 掘金(YY)
2.3、vite 中的 Module Federation 计划
vite 插件 vite-plugin-federation 提供了对标 webpack 的能力,只是加载的形式改成了 ESM,其插件接口设计与 webpack 的参数设计简直是一样的。vite-plugin-federation 也是 vite 官网举荐和收录的插件,已收录在社区插件列表 GitHub – vitejs/awesome-vite: ⚡️ A curated list of awesome things related to Vite.js。
2.4、具体到咱们的场景中
工单工作台利用,作为 remote 端,它能够提供工单详情,订单详情和创立工单,赔付模块等多个页面级组件。
IM 或电话工作台利用,作为 host 端,能够应用上述组件。
3、具体实际
因为咱们两个我的项目都应用的是 vue3 + vite 计划,所以应用 vite-plugin-federation 插件 是咱们最佳的抉择。首先须要在 host 端和 remote 端装置插件,如下命令:
yarn add @originjs/vite-plugin-federation -D
留神: 此处为了展现方便使用了官网插件,理论因为我的项目相干的起因,咱们对官网插件进行了一些改变。
3.1、工单工作台作为 remote 端的配置
(1) 在插件内注册须要提供的组件
并且提供须要共享的三方依赖
(2) 配置实现后打包
在 remote 端打包后会生成对应的入口文件,chunk 文件及依赖包文件:
3.2、IM 和电话工作台作为 host 端的配置
(1) 插件配置,设置近程包地址
(2) 援用及注册组件 , main.ts 文件 如下
这时须要留神,ticket-share 为 host 侧在 vite 插件中注册的包名,Detail 为 remote 端裸露 (exposes 字段) 申明的组件名。 除了在全局注册,还能够在任意须要援用的中央援用。
(3) 组件的应用
在须要的中央引入应用,并依据业务状况传递 props,props 的应用形式与一般组件无异。
此时咱们曾经实现了全副配置,尔后咱们只有打包上线运行即可。
五、重构之后的成果
1、加载速度
再来看一段视频
大家能够与最开始的视频比照一下,能够看出十分直观的差别。
首屏 | 二次(非首屏) | |
---|---|---|
iframe | 7076ms | 2594ms |
模块联邦 | 1279ms | 428ms |
留神:上述数据由测试环境进行十次均匀失去,测试值更靠近 TTI。
从数据中能够看到,在首屏环境(即无任何缓存)下模块联邦加载速度进步了 5.5 倍。而在二次加载场景中(此场景是客服应用频率最高的场景),速度进步了 6 倍!
2、内存
咱们仍旧依据开始的场景,模仿客服关上多个用户多个工单 / 订单详情的情景,如上图,首先能够发现:
- 没有内存透露!
- 内存占用在雷同的工夫内,最高只达到了 55MB,并回落。
- 单个工单详情关上内存增幅从 10MB 升高到有余 1MB。
因为除了模块联邦带来的间接收益,咱们还享受到了它的附加收益,因为模块联邦自身援用的是一个组件,所以利用 vue 组件自身的个性,多个工单详情咱们能够复用同一个实例!
3、客服反馈
上线之后,咱们再也 没有收到相干的任何负面反馈,例如打动工单详情慢,或者说浏览器解体的反馈没有了!
六、后续布局
1、模块联邦的毛病:保护共享库
它并不是没有任何毛病,在配置过程中咱们能够看到须要 配置 share 字段,即不同我的项目须要共享的三方库,例如 A 我的项目应用 vue,B 我的项目也应用 vue,那么就须要将 vue 申明进去,插件会将 vue 主动宰割进去,这样 A,B 我的项目能够共享应用了,在 remote 端和 host 端都须要申明,申明如下:
shared: {
vue: {
// remote 端该字段为 requiredVersion
version: '3.1.5'
},
axios: {version: '0.21.1'},
vuex: {version: '4.0.0'},
'vue-router': {version: '4.0.8'}
}
然而,这里对开发同学有十分不敌对的点:
- 须要将组件共享的包都手动找进去
- 共享有时是强制的,如果漏了某些包,可能会导致页面报错或解体,设想一下页面同时有两个 vue
- 同一个库,有时须要保护在约定的版本范畴内,有时一个包太老或太新也会在加载时报错
简而言之,就是对共享包的保护老本很大!
2、解决思路
- 须要建设日常及生产构建时 hook
- 而后自建服务监听这些 hook,比照三方库的包差别及其版本差别, 并抛出相应正告
- 引入巡检,构建实现后对近程模块局部进行查看,因为不是每个改变都会使测试回归,但每个改变都可能引起页面解体。
- 对插件进一步封装,使开发者无需关怀三方依赖的治理。
3、与去利用化 assets 公布的抵触
- 因为 assets 公布人造须要引入版本号,因而每个迭代所有的资源的地址都会带入版本号
- 近程组件援用须要按约定确定一个 remote 端的入口文件地址,该地址根本是固定的
所以,目前 remote 端我的项目还不能应用 assets 公布,接下来一是能够用接口的形式代替,二是须要团队之间协商解决这个问题。
4、更大方向的畅想
还记得“能够打造一个去中心化的利用集群”那张图吗?组件的援用不仅仅呈现在团队外部,也可能呈现在团队间共享,例如创立工单这个模块就会被情报系统这样的团队援用。
即各个团队间,或团队外部的组件或模块相互援用的,目前次要依附 iframe 解决的,都能够应用模块联邦解决。
而公司外部也能够有这么个平台,汇合模块联邦的团队,业务模块展现治理,共享依赖包的校验,正告或主动修补等等性能,来实现业务级别的团队内外高效合作。
扩大浏览:
【1】https://juejin.cn/post/685656…
【2】https://github.com/umijs/qian…\
【3】https://webpack.docschina.org…
【4】https://juejin.cn/post/684490…
【5】https://juejin.cn/post/691149…
【6】https://github.com/vitejs/awe…
【7】https://github.com/vitejs/awe…
文 /LIUZHOUCHANG
关注得物技术,做最潮技术人!