解密微前端:浅谈微前端生态
解密微前端:浅谈微前端生态
这篇文章算是我对在阿里做微前端的一个总结吧,没有写的事无巨细,更像是一个对自己的备忘录,很多地方因为做的比较久了记忆也比较模糊了我也会慢慢补充。
我对微前端的理解
当我们在谈论微前端的时候,往往提到的是一个前端的架构模式:一种瓦解前端“巨石应用”的分治方案。但是在我看来,随着微前端在企业级中后台应用的广泛使用,我们在谈论微前端的时候已经衍生到一整套前端生态闭环(加载器、路由、发布系统、应用插件等等),甚至当这套生态跑流畅之后可以落地出一整套微前端的解决方案。
因此,我对微前端的理解就是:
- 前端架构
- 生态闭环
- 解决方案
而抛去以上架构层面的认知,我觉得微前端首要解决的问题是团队合作 / 效能所带来的前端工程化问题。
架构背景
我一直认为当我们谈论生态闭环或者解决方案的时候配合架构背景会更有说服力,也能让大家理解我们很多地方为什么要这么做。
之前微前端系列的第一篇文章已经详细介绍了我们的项目架构背景,这里在简单回顾下,详情见《解密微前端:"巨石应用"的诞生》
模版架构
弊端:
- 后端解析模版,挂载模版;
- 后端管控路由,前端失去了对路由的掌控权,并且多个团队路由规则管控较难;
- 主子应用作用域不隔离;
- 每一次前端发布需要先发布静态资源再发布模版,发布繁琐容易出错;
iframe 架构
诉求:
- 需要不依赖后端模版;
- 需要管控路由并制定统一的路由规则;
- 主子应用的沙箱隔离;
- 尽量对子业务的改动做到最小化,很多业务包袱很重;
- 快速落地并实现高可用;
弊端:
- 通信方式简单,简单的 postmessage API 并不能满足业务的需求;
- 样式割裂,iframe 会导致诸如 Dialog 这样子的全局蒙层仅在 ifame 区块内展示,使我们系统更像是“拼凑”出来的;
- 性能瓶颈,路由的切换会导致 iframe 内子应用的重新加载,性能堪忧;
- 跨域问题,chrome80 的 samesite 策略会导致 iframe 方案的跨域 cookie 无法带给后端;
微前端架构
诉求:
- 改动成本;
- 沙箱隔离;
- 兼容 iframe;
- 路由不变性;
- 通信不变性;
- 灰度控制、容灾降级;
- 适配三端:pc、桌面端、POS 机;
- 子应用存在投放不同平台的场景,尽可能让子应用对投放平台无感知,宿主环境无感知;
- 兼容搭建平台;
业界痛点
这里我在搭建微前端生态的时候和阿里的其他的团队做了交流,收集了其他团队在微前端生态搭建过程中的遇到的痛点:
- 微前端生态需要适配搭建系统;
- 需要具有兼容 icestark、qiankun、singleSPA 的能力;
- 兼容已有的 iframe 架构以及 iframe 生态;
- 业务体量大,稳定性要求高;
- 适配已有的前端基建(发布系统、埋点系统、监控系统);
我们在微前端生态相关的建设
微前端框架
微前端框架在我们的技术选型是 qiankun,当时的选型目标比较简单粗暴:
- 接入简单侵入少:我不想接入一套新的方案直接对老系统重构;
- 兼容 iframe 生态:已经存在比较成熟的生态体系,并且已经累计接入了近百个子应用;
- 没有足够的人力自建 / 维护自由的微前端框架:只有我一个人力,并且不鼓励重复造轮子;
而在我看来作为微前端生态中最终要的一环,微前端款框架应该集成了最核心的功能:
- 子应用加载
- 沙箱隔离
- 路由劫持
- 应用间通信
前三点都是采用的框架本身提供的能力,而应用间通信我们采用了自建的方案。
为什么自建通信模型?
其实框架侧提供的通信方案基本上能满足大部分业务场景,但是我们再次基础上有着更高的诉求:
- 已有比较成熟的 iframe 通信方案,能否兼容 iframe 方案,降低 iframe 应用改造成本;
- 能否支持在 iframe 和微前端两套接入方案下自由切换而子应用无感知;
为此,我们在 iframe 通信模型的基础上,基于宿主环境判断封装了微前端的发布订阅模型,采取完全相同的 API,子应用不再关心自己的接入方式和宿主环境。
应用管理
路由管理
在聊应用管理之前我想先聊一下路由管理,对于大型的 B 端系统,一套合理的路由规则是极其重要的,尤其我们的系统是对外使用的:
- 前期需要定好规则,不能随着性子随便改变,用户很多都直接保存了对应页面链接;
- 子应用间存在跨应用间路由跳转的场景,合理的路由规则也便于跨应用层级的路由控制和路由管理;
- 我们也需要基于路由做粗力度的权限控制;
这里首先在路由约束下,我是采取了下面的规则:/:platform/:privilegeKey/:childHash
- platform:平台:pc、desktop、pos;
- priviateKey:权限点,和子应用 microKey 有 n - n 关系;
- childHash:子应用实际 hash,注册为微前端子应用时需要以/:platform/:privilegeKey 作为 basePath;
子应用版本控制
对于国内主流的微前端方案来说都提供了两种方式的接入:
- entry:直接配置子应用的 html 链接,框架测分析解析子应用 html 并实现资源注入;
- 资源配置:配置 js、css 等 cdn 资源从而实现资源注入;
这两种方式决定了发布系统如何配合我们的微前端生态,这里我们采取的是第一种方案。
为什么采用 entry 模式?
- 子应用存在投放多个业务平台的场景,不能因为接入一套方案而放弃其他,entry 形式也给了子应用作为应用独立运行的能力-;
- 子应用灰度:html entry 在发布平台天然存在版本控制;
容灾(应急策略)
在容灾降级这边,因为我们已经有了一套比较成熟的 iframe 生态,并且微前端方案在我设计的时候就多处做好了向下兼容的策略,因此我们对于容灾降级就是降级成 iframe 方案,对于 iframe 依旧异常的场景就只能通过监控报警来兜底了。
-
降级 iframe
- 热降级:捕获挂载错误自动降级 iframe;
- 冷降级:手动移除微前端配置降级 iframe;
-
监控
- 微前端配置加载监控;
- 子应用挂载成功率监控;
- 子应用内部异常捕获监控;
子应用赋能
在我看来,子应用赋能是微前端中不可或缺的一环,下面主要向大家介绍下我在子应用赋能方面所做的一些事。
通信模型
通信模型上面已经简单提过了,这里就不过多赘述了。
自动埋点
主子应用同时挂载埋点 SDK 的话是没有意义的,设置会增加数据“噪音”,因此仅需要主应用挂载 SDK 即可。我这里基于集团的埋点 SDK 做了二次封装,在主应用 ready 的时候挂载埋点 SDK,并以当前的 microKey 作为埋点的 id 聚合子应用的埋点,并且对子应用开放埋点调用事件。
总结起来就是:
- 聚合埋点 SDK;
- 自动采集 PV / UV;
- 手动触发埋点事件;
- 埋点扩展:业务级全埋点自动采集;
异常监控
和埋点一样,异常监控我们也采用主应用挂载的形式,并以 microKey 做监控聚合。但是不同的是,监控这块我们暴露了卸载主应用监控的事件给子应,接入的不同团队的不同应用可能采取了完全不同的监控体系,而监控 SDK 的底层远离都是劫持 fetch 等原生事件去做的,不同的 sdk 间很可能出现污染。
路由中台
在路由规则和权限点的基础上,我们也落地了自己的路由管控配置平台,我们收口了全部子应用间路由跳转的 url,替换为按照路由事件 + schema 的形式让子应用调用,这样在子应用自有链接随着业务迭代的时候只需要同步到路由中台,便不需要其他子应用同步更新路由链接了。
其他赋能
这里还有很多根据我们业务域定制的一些能力,我就不一一细说了:
- 单子业务域多实例挂载;
- 子应用后台挂起、keepalive、保活;
- 不同的浏览器访问行为:打开新页、重定向(无刷)、重定向(刷新);
- 不同平台的适配层:pos、桌面端、浏览器;
- ...
最后
最后简单说下我个人认为的微前端最佳实践吧:
- 大型 B 端系统,涉及多业务域,多团队维护,子业务间耦合度较低,业务边界清晰;
- 不能要求子应用要多,但是不能太少,一两个子应用微前端失去了该有的价值,或者说有更合适的替代方案;
- 团队内已经无法忍受 iframe 或其他替代方案带来的痛点;
- 微前端会伴随着配套周边的生产,考虑好 ROI;