微前端落地系列-复盘
❝前沿:哈喽大家好,我是树酱🌲,好久不见。本文主要为了做复盘,在去年基于qiankun微前端架构的门户建设中,遇到的一些问题,可能你会认为:“哇,这也算问题吗?太简单了吧”。主要是分享在我认知体系内是如何解决的,如果对其中一些解决方案有更好的建议,记得在评论区留言~
❞
上图为落地过程中遇到的一些问题,接下来围绕这些问题跟大家分享我的认知体系是如何去解决的
1. 应用权限控制如何做?
❝权限控制一般分为:路由权限、按钮权限(视觉权限)等,下面举例说明
❞
路由权限:比如当用户从门户中登陆后,要访问应用A或者应用A下的某个菜单页面时,但该用户并没有该应用的访问权限,我们需要拦截它,不让它进入
按钮权限 (视图权限):比如当某个用户不存在对某种资源进行删除的权限的时候,我们会将原有的删除操作按钮给隐藏,以此来实现按钮
❝👦 啊敏同学:那我们怎么知道是否有权限,或者说怎么区分资源类型?
❞
🌲:mark,首先我们先给每个资源定义一个code编码,你可以理解为对这个资源的唯一标记,它的身份id,比如我们可能是应用、菜单或者按钮。针对不同类型的资源,可以做用规则区分,比如👇
1.1 路由权限
❝👦 啊乐同学:那编码规则确定了,我们如何控制呢?
❞
🌲:我们来假设一个用户有一个资源集合的权限
[appliction:monitor、menu:monitor:flume、button:monitor:flume:delete]
首先先说路由权限控制,主要是为了判断该用户是否有应用或者菜单的访问权限,我们一般可以在router.beforeEach
导航守卫中做拦截,一般分为两种情况
动态路由:原先并未添加路由,根据上文提到的资源编码来动态添加路由,可参考🌲树酱之前写的关于门户的前端权限控制[1]
静态路由:已经初始化好路由,通过统一在门户这个主应用的路由根据获取的资源编码来判断当前访问的用户是否有应用访问权限,如果没有则进行拦截,如下所示是门户这个主应用对路由的处理,因为当子应用加载后,主应用会劫持原本子应用的路由,举个例子如下 👇
上图中的hasPerssion
方法就是通过判断该用户是否有某个应用的资源编码,以此来判断是否有权限访问,本质上就是new RegExp
正则匹配,如果没有权限则跳转到无权限访问页面
1.2 视觉权限
❝啊敏同学:那按钮权限呢?如何处理
❞
🌲:同样需要依赖到资源编码,然后通过自定义指令,比如v-perms
来控制,指令源码可点击👉指令控制[2] 如下图所示是一个按钮的具体使用
至于v-perms
指令我们是如何给每个子应用复用,通过门户主应用去注入到子应用生命周期, 子应用接收如下👇
❝啊敏同学:树酱,你上面提及的按钮权限控制是基于
❞<template>
, 那如果是直接render函数渲染咋搞?
🌲:render函数中原理也是一样的,只不过把指令换了一种方式,通过工具库里面封装findPermission函数,来控制style的display属性值,当然你也可以用上文提到主应用给子应用的方式注入一个工具函数的方式,以此达到复用。如下所示👇
2.应用的异常监控
❝当门户落地后,如何去监控子应用的异常信息就显得很重要,毕竟不同环境可能会出现不一样的情况,那如何去追踪和定位呢?
❞
我们在qiankun的api文档中找到了addGlobalUncaughtErrorHandler
方法,用来监听全局的未捕获异常
比如说我要监听应用加载失败,那我可以捕获到的错误信息中的信息提示来做正则匹配
然后通过bus通信,通知页面显示应用加载失败页面,如下所示
❝👨🎓 啊豪同学:那你们怎么将异常信息上报的呢?
❞
🌲:我们是通过sentry
去做异常信息上报的,sentry本身会做异常捕获,但是为了让主应用能够统一捕获子应用的异常信息,做统一异常信息维护管理,所以在addGlobalUncaughtErrorHandler
中做了主动上报
如果想了解sentry如何二次封装,可以看树酱之前写的 前端监控那些事[3]
3.如何让新的子应用实现快速集成
❝前言:我们知道qiankun架构中一个子应用要集成到主应用中,是需要创建生命周期函数,比如mounted等以及修改打包方式。那如何快速让新的子应用实现快速集成呢?
❞
我们是通过打造一个简易版的脚手架工具,把涉及相关的功能用一套模版维护起来,然后通过维护好的这个模版,然后通过脚手架创建新项目,本质上就是拉取这个模版,如下图所示
具体开发可以参考之前写的《前端那些事》从0到1开发简单脚手架[4]
4.如何动态注册应用?
❝前沿:为了让主应用可以去访问不同的子应用,我们需要在配置文件中定义好每个子应用的入口entry以及访问名称,以此来注册子应用,我们一般会不同的环境有不同的配置,比如下图所示
❞
❝👨🎓 啊斌同学:那这样的话,每次修改子应用的entry或者新增新的子应用都得重新编译门户这个主应用
❞
🌲:是的,本地配置化是会存在这样的问题,我们可以搭建一个配置中心来维护,然后通过接口调用的方式来获取不同环境的,像下面这样👇
5.部署中遇到的问题
❝前沿:部署微前端体系门户涉及到私有云部署,公有云部署,还有基于容器化部署等等。过程中遇到一些问题
❞
5.1 主应用加载子应用静态资源跨域咋搞?
本质上是因主应用是通过fetch去获取子应用的静态资源的,然后通过正则去解析出来子应用的静态资源信息,然后fetch下来,所以必须要求这些静态资源支持跨域,如何配置如下图所示,通过设置允许源了
Access-Control-Allow-Origin
:跨域在服务端是不允许的。只能通过给Nginx配置Access-Control-Allow-Origin *后,才能使服务器能接受所有的请求源(Origin)
5.2 主应用加载子应用的静态资源不是最新,导致加载失败?
本质上就是子应用更新了代码,而主应用在fetch子应用资源的时候,加载到缓存的资源,导致加载资源失败,那么怎么解决呢?我们可以在子应用的nginx中,设置cache-control
,在每次请求资源的时候都检查是否更新。
5.3 如何让每个子应用都拥有通用的ngixn配置?
为了解决以上问题,又要保证通用性,可以针对每个子应用都是同样的nginx配置,这时候可以通过在dockerfile
中定义,在打包到容器时,把nginx.conf
也打到容器中
5.4 如何正确部署主应用和子应用?
主要是两种方案:
1.主应用和子应用部署到同一个服务器
这种情况适合公司服务器数量较少,核心就是把主应用部署在一级目录,其他子应用放在二级目录
2.主应用和子应用分别部署在不同服务器
这种情况又分为两种,一种是所有子应用都在一台服务器,一种是不同子应用在不同服务器,独立运行。
最后,以上两种方式都有好有坏,具体看你搭建的系统是内部以ip访问为主还是外部访问域名为主,去根据实际情况应用。如果是内部系统建设,子应用以内部访问ip为主,子应用都在独立服务器,无需在配置过多域名,那可以直接用方案2,那如果是对外且域名有限,那方案1或许更合适。
具体的配置方式,我看qiankun官网文档已经更新,可查阅🔗文档[5] 这里就不重复介绍
Reference
关于门户的前端权限控制: https://juejin.cn/post/6900872985876856839
[2]指令控制: https://juejin.cn/post/6900872985876856839
[3]前端监控那些事: https://juejin.cn/post/6844904080586850311#heading-4
[4]《前端那些事》从0到1开发简单脚手架: https://juejin.cn/post/6844904137709060104
[5]🔗文档: https://qiankun.umijs.org/zh/cookbook#%E5%9C%BA%E6%99%AF-1%EF%BC%9A%E4%B8%BB%E5%BA%94%E7%94%A8%E5%92%8C%E5%BE%AE%E5%BA%94%E7%94%A8%E9%83%A8%E7%BD%B2%E5%88%B0%E5%90%8C%E4%B8%80%E4%B8%AA%E6%9C%8D%E5%8A%A1%E5%99%A8%EF%BC%88%E5%90%8C%E4%B8%80%E4%B8%AA-ip-%E5%92%8C%E7%AB%AF%E5%8F%A3%EF%BC%89