cover_image

CMS后台qiankun微前端落地

马晓林 前端极客志
2020年11月14日 10:45

伏羲商办后台建设背景:

伏羲项目商办后台(伏羲CMS),作为服务于58商办C端的后台项目,目前涉及联合办公和写字楼两个类目,提供了相关业务操作、C端广告配置、数据统计、角色权限管理等模块。作为商业地产的新平台,伏羲CMS具有功能迭代灵活、业务扩展迅速等特点。之前的问题是:

  1. 多个不同技术栈系统,多个运营入口;

  2. 随着功能迭代,规模逐渐庞大,通过项目内的模块化无法解决业务膨胀的问题,每次开发需要全量上线。

总而言之,我们希望的是项目分离,运营聚合。要做的就是将已有的“巨石应用”拆解成多个可独立开发部署的子项目,然后整合为统一入口,UI风格一致的服务平台,因此萌生了微前端改造的想法。

图片

总体分析下来,最后一种方式更符合我们的预期。为此我们又尝试了业内较火的两个微前端框架single-spa和qiankun,最后选择了qiankun,主要原因是它的两个特点:

  • HTML Entry:相较与JS entry而言天生具备样式隔离的特性

  • JS 沙箱:保证子应用之间的全局变量不会互相干扰实现软隔离。

项目设计

我们做了配套的 Node 层设计,使用前端 + 服务端作为整体方案,子应用既可以独立提供服务,亦可以作为主应用的一个子模块。系统的整体架构图如下:

图片

首先做的是将项目合理拆解,拆分的原则是尽量避免子应用之间的业务耦合以及粒度不宜太细。最终拆为一个主应用和三个子应用。

主应用:

主应用原则上不包含任何的业务逻辑,功能主要有三:

  1. 页面主体框架的渲染: 比如顶栏等一些通用模块;

  2. 用户信息权限控制: 用户登录/登出,并将用户信息和权限利用通信机制传给子应用;

  3. 子应用加载/卸载: 主应用获取当前环境子应用配置,根据接口返回的用户权限及捕获全局的路由变化加载 / 卸载子应用。在子应用挂载前,会劫持HTMLHeadElement.prototype.appendChild对不同资源类型做处理,对于style标签会在应用生效的时候加入样式;对于script标签,则在资源加载完之后通知监听器script标签生效。

app.ts如图所示

图片

9~12行:动态获取子应用config(配合多套环境配置);
22~35行:获取用户信息,然后根据用户获取子应用权限并解析成路由配置和静态路由合并;
38~42行:将用户信息注入到store中,全局调用或透传给子应用。

子应用

子应用在被主应用启动后,会接管系统路由,匹配到各自独立的路由规则、菜单管理等,形同一个独立运行的应用,可以单独测试、上线。其中用户数据在挂载期间做了判断:如果是独立启用,则调用接口获取;如果作为微前端的子应用,则从主应用中获取。

图片

node端部署时的路由配置

本项目中子应用和主应用使用的都是history模式,在项目部署在node端时,注意将各子应用的base配置需要追加主应用的base配置,才能保证微应用的实例正确跳转。

配套设施

方案的落地不仅仅体现在能实现基本功能,更要考虑新的子项目接入、对不同环境的支持以及项目层级权限分配等问题,才能保证其持续运行。为此我们设计了相关的配套设施。

  • 权限管理模块:提供用户访问权限的配置入口,根据权限数据自动生成子应用菜单和路由规则,便于后续页面扩展

  • 多套环境配置:将测试、沙箱及线上的qiankun配置提出来放在node层,根据部署环境自动to给前端项目,无须手动修改

应用之间的通信

让分离的应用之间进行通信,本质上是离不开中间媒介(比如全局对象)。CMS项目中,我们需要透传的数据是用户信息。实现方式 是主应用注册一个 MicroAppStateActions实例并导出,fetch到用户信息后将其设置为globalState;子应用通过注册观察者来监听globalState的变化获取最新的用户信息。

对于微前端项目,过多的应用通信会增加项目之间的耦合性,这也违背于将子应用做“独立应用“而非”独立模块“的初衷,因此当前这种Action的通信方式应足以满足实际需要。

整个项目运行时加载及路由策略如下:

图片

JS隔离和css隔离

qiankun具有天生的css隔离,因为它采取的是html entry的方案,通俗说就是一个“资源加载清单”,子应用切换时,浏览器会对所有的样式表的插入、移除做整个 CSSOM 的重构,这样即能保证,在一个时间点里,只有一个应用的样式表是生效的。

js隔离的核心思想是在子应用挂载/卸载的过程中,避免其对全局变量的污染。实现方案是利用window.proxy生成环境快照,在激活沙箱时查询到子应用的独立状态池并还原子应用状态;在关闭沙箱时删除或恢复在沙箱运行期间新增或者修改的全局变量,从而还原到子应用挂载前的状态。

图片

改造成果

如下图所示,在改造前,每次有迭代需求时,要么是在原项目上不断堆积新模板和页面,每次上线全量部署,要么就是将独立项目以iframe的形式接入,再花大量精力解决隔离问题。改造后,后续需求迭代开发不再盲目的往一个项目上堆积,而是合理的拆分称小型的应用单独测试部署,降低了上线风险;若有其他团队接收开发任务, 也无需cover整个项目状态,且可以在符合接入规则的情况下自由的选择技术栈,提高了项目维护性。

图片

目前有2个react子应用和1个vue子应用接入到主应用中。

总结

我们从项目的设计、拆解到产出较完整的方案,不仅是一次较成功的微前端尝试,也为后续公寓侧B端项目的升级重构提供了实践基础,但在不同业务上设计完善的微前端体系会面临更多挑战。我们会继续探索,将微前端带给B端的收益提升到最大化。


继续滑动看下一个
前端极客志
向上滑动看下一个