jiewu(公务)

qiankun?这次我选了wujie!写在最前:本文面向对无界和微前端有一定了解的人群,不再对微前端的概念和无界的基础使用方式做解释说明前言头条上搜wujie,那么大眼一看,好像全都是介绍的,并没有几个落地方案的分享。正好我上个月把部门内三个业务系统

qiankun?这次我选了wujie!

写在最前:

本文面向对无界和微前端有一定了解的人群,不再对微前端的概念和无界的基础使用方式做解释说明

前言

头条上搜wujie,那么大眼一看,好像全都是介绍的,并没有几个落地方案的分享。正好我上个月把部门内三个业务系统用wujie整合了一下,记录成文章和大家分享一下。(为什么不用qiankun?qiankun之前做了好多次了,这次想尝个鲜~)

背景说明

笔者部门内有三个管理系统,技术栈分别是:

A: Vue2 Webpack4 ant-design-vue@1.7.8:该项目是部门内“司龄”最长的,从部门成立之初起,所有的业务都堆在里边。

B: Vue3 Webpack5 ant-desgin-vue@3.2.20:由于业务目标不清晰以及前端开发各自为战,部分需求被拆出来了一个单独的项目进行开发,但实际上然并卵。

C: Vue3 Vite2 ant-design-vue@3.2.20:为了响应领导“统一前端UI规范”和“低代码降本增效”的号召,这个项目应运而生,使用JSON Scheme渲染列表页 手写Form表单的形式开发需求。

没错,就是3个纯业务向的管理系统。对接我们部门的大部分业务人员,日常都至少需要操作3个系统,甚至有些人还会用到别的部门的系统,甚至有的人习惯打开多个浏览器tab页来回切换对比同个页面的数据。。。poor guy。。。浏览器密密麻麻的全是tab页。。。

契机

某天,发生了如下对话:

领导:业务部门老大说,系统间来回切换太麻烦了,有没有办法解决这个问题?我:有,微前端。领导:之前XXX不是用qiankun做过吗,问题很多,不了了之了。我:我看过他的代码,没有什么大问题,都是一些细节方面的小bug,而且还有别的微前端方案可以选择。领导:行,你安排一下,尽快上线我:好的。( 打工人被安排任务就是这么朴实,无华,且枯燥。。。)

为什么选择无界?

(此处省略万字长文对比分析qiankun、micro app、single-app…)

直接摆出站在个人角度以及团队技术、业务背景下选择无界的原因:

喜欢吃螃蟹:之前有过多次qiankun的落地经验,直接上qiankun,一点都不酷。(第一次了解到无界是22年的10月份左右,彼时的无界还在beta版,想尝尝鲜。况且就算使用无界出了岔子,也有信心能cover住)子应用改造,侵入程度低:就像文档中宣传的那样,我用公司的项目跑demo,除去登录态的因素外,基本可以说是0改动接入,当时脑海中只有2个字—-牛X!(当然,仅仅这样接入,离上生产的标准还相距甚远;而且最后我还是选择了类似qiankun根据宿主应用动态选择layout的布局方案,改造成本也可以说是不算低了,这个暂且按下不表)方便独立开发、部署:与第2点相似但又不同:现有的项目有独立的域名、部署方案、且在生产环境已经稳定运行,在保留这些基础的前提下,无界的iframe方案算是最理想的出路(另外也有一点私心,如果生产环境的无界挂了,业务人员可以直接使用老的域名访问独立的子应用进行业务操作,毕竟出了生产事故是要通报批评的)

综上所述,确实没经过太多深思熟虑,想用就用,干就完了

jiewu(公务)

正常情况下,主应用判断url参数做跳转的逻辑不管放在哪里,都存在目标子应用未加载完成的可能性。

(如果你说每个子应用component的afterMount事件里都写一遍,fine,你赢了)

这个时候,只需要对无界的eventBus稍作改动,即可满足需求:

import WujieVue from "wujie-vue3";import { AppCollection } from "@/constant";import store from '@/store';const { bus }=WujieVue;type EventList="LOGIN_EXPIRED" | "EVENT_NAME1" | "EVENT_NAME2"; // 一些事件类型涉及到公司业务,这里省去了type EventBusInstance={$emit: (e: EventList, params: Record)=> void;$on: (e: EventList, fn: (...args: any[])=> void)=> void;$registerMountedQueue: (app: AppCollection,e: EventList,params: Record)=> void; // 将事件注册到子应用mount成功的的事件队列中$cleanMountedQueue: (app: AppCollection)=> void; // 清空子应用mount事件队列};type Queue={[app in AppCollection]?: any[];};let instance: EventBusInstance | undefined=undefined;export default ()=> {const queue: Queue={};if (!instance) {instance={$emit: (event, params)=> bus.$emit(event, params),$on: (event, fn)=> bus.$on(event, fn),$registerMountedQueue: (app, event, params)=> {const isMounted=store.state.globalState.appMounted[app]; // store中存储了子应用是否mount完成的状态const fn=()=> bus.$emit(event, params); // 子应用已挂载完成可以直接通信if (isMounted) return fn(); if (queue[app] && queue[app]!.length) {queue[app]!.push(fn);} else {queue[app]=[fn];}},$cleanMountedQueue: (app)=> {while (queue[app] && queue[app]!.length) {const fn=queue[app]!.shift();fn();}},};} return instance;};

为每个子应用都维护一个事件队列,主应用通过$registerMountedQueue注册事件时,若对应子应用已经mount完成,则直接emit进行通信;若子应用没有mount完成,则将注册的事件推入队列中。

子应用afterMount钩子中调用$cleanMountedQueue,清空属于自己的事件队列。

目前根据业务需要,只做了这一点封装,后续有可能会继续补充。

当然前边提到的这个场景,肯定还有许多不同的解决方案,根据自己的项目因地制宜才是最重要的。

5.子应用afterMount生命周期

上边第4点已经提到过,子应用afterMount钩子中要做两件事情:

store中保存自己mount完成的状态。调用$cleanMountedQueue清空自己的事件队列。

6.子系统网络请求管理

网络请求管理,主要解决的是跨域问题,分两种:

调用后端服务跨域 如果你的用户鉴权是基于cookie的,那最方便的就是使用无界推荐的方法:将主应用的fetch自定义改写后传给子应用。如果你的用户鉴权是基于JWT或者你使用了其他的http请求库,赶快买上两杯咖啡贿赂一下运维大佬,给子应用对应的服务配置下Response Header,支持主应用域名的跨域资源共享。但是要切记,生产环境不要使用Access-Control-Allow-Origin: *。请求子应用静态资源跨域

刚才为啥要让买两杯咖啡,因为一杯是改后端服务支持跨域,还有一杯是改前端静态资源服务器(比如Nginx)支持跨域。

jiewu(公务)

行吧,第一版先到这里,欢迎真诚交流,但如果你来抬杠?阿,对对对~ 你说的都对~

作者:Elecat
链接:https://juejin.cn/post/7297592806569164810

本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 sumchina520@foxmail.com 举报,一经查实,本站将立刻删除。
如若转载,请注明出处:https://www.shpfj.com/23357.html