领导:我有个需求,你把我们项目的技术栈升级一下

故事的开始

在一个风和日丽的下午,我正喝着女神请的9.9咖啡,逛着掘金摸着🐟,一切的一切都是这么的美好。

霎那间,只见耳边响起了声音,"系统觉醒中,请。。",啊?我都外挂到账了?

呸,是"帅哥,领导叫你去开会"。

"哦",某位帅哥站了起来,撇了撇帅气的刘海,走向了办公室。

会议室情节

"咦,不是开会吗,怎么就只有领导一个人"。

昏暗的灯光,发着亮光的屏幕,在幽闭的空间里气氛显得有那么一丝的~~~暧昧,不对,是紧张。

"帅哥你来了,那我直接说事情吧",领导说到。

突然我察觉到那么一丝不安,但是现在走好像来不及了,房门紧闭,领导又有三头六臂,凭着我这副一米八五,吴彦祖的颜值的身躯根本就逃不了。

"是这样的,上面有个新需求,我看完之后发现我们目前的项目技术包袱有点重,做起来比较麻烦,看看你做个项目技术栈升级提高的方案吧"。

听到这里我松了一口气,还好只是升级提高的方案,不是把屁股抬高的方案。

进入正题

分析了公司项目当前的技术栈,确实存在比较杂乱的情况,一堆的技术包袱,惨不忍睹,但还是能跑的,人和项目都能跑。

技术栈:vue2全家桶 + vuetify + 某位前辈自己开发的组件库 + 某位前辈搞的半成品bff

我用了一分钟的时间做足了思想功课,这次的升级决定采用增量升级的方案,为什么用增量升级,因为线上的项目,需求还在开发,为了稳定和尽量少的投入人力,所以采取增量升级。

这里会有很多小伙伴问,什么是增量升级啊,我会说,自己百度

又经过了一分钟的思想斗争,决定使用微前端的方案进行技术升级,框架选择阿里的qiankun

这里又会有小伙伴说,为什么用qiankun啊,我会说,下面会说

微前端---qiankun

为什么使用微前端,最主要是考虑到他与技术栈无关,能够忽略掉一些历史的包袱。

为什么要用qiankun,最主要还是考虑到稳定问题,qiankun目前的社区比较大,方案也多,出了问题能找到方案,本人之前也有使用过的经验,所以这次就决定是它。

技术为业务服务,在面对技术选型的时候要考虑到现实的问题,不能一味的什么都用新的,稳是第一位

那么应该如何在老项目中使用微前端去升级,我给出了我的方案步骤

  1. 对老项目进行改造(路由,登录,菜单)
  2. 编写子应用的开发模板
  3. 逐个逐个模块进行重构

下面会和大家分析一下三个步骤的内容

老项目的改造(下面大多数为代码)

第一步,我们要将老项目改造成适合被子应用随便进入的公交车。🚗

先对老项目进行分析,老项目是一个后台项目,大多数的后台项目布局都是上中左布局,头部导航栏,左边菜单栏,中间内容。那么我们只需要当用户选择的菜单属于微前端模块时,将中间内容变成微前端容器就好了。

那我们现在制作一个layout,里面的UI库我懒得换了,讲究看吧🌈

js 复制代码
// BasicLayout.vue
<a-layout>
    <a-layout-sider collapsible>
    //菜单
    </a-layout-sider>
    <a-layout>
      <a-layout-header>
      //头部
      </a-layout-header>
      <a-layout-content>
          //内容
        <router-view/>
        <slot></slot>
      </a-layout-content>
    </a-layout>
</a-layout>

然后对App.vue进行一定的修改

js 复制代码
// App.vue
<a-config-provider locale="zh-cn">
    <component v-if="layout" :is="layout">
      <!-- 微前端子应用的容器,插槽紧跟着view-router -->
      <div id="SubappViewportWrapper"></div>
    </component>
        // 初始化子应用时传入容器,这个容器不能后续修改,目前方案是将下面的容器动态append到SubappViewportWrapper 
    <div id="SubappViewport"></div>
</a-config-provider>
  
import { BasicLayout, UserLayout } from '@/layouts'
import { MICRO_APPS } from './qiankun'
import { start } from 'qiankun';
export default defineComponent({
components: {
    BasicLayout,
    UserLayout
},
data () {
    return {
      locale: zhCN,
      layout: ''
    }
},
methods: {
isMicroAppUrl (url) {
    let result = false;
    MICRO_APPS.forEach(mUrl => {
        if (url.includes(mUrl)) {
          result = true;
        }
    });
    return result;
},
checkMicroApp (val) {
    if (isMicroAppUrl(val.fullPath)) {
        // 展示微前端容器
        console.log('是微前端应用....');
        document.body.classList.toggle(cName, false);
        console.log(document.body.classList);
    } else {
        // 隐藏微前端容器
        console.log('不是微前端应用');
        document.body.classList.toggle(cName, true);
    }
    const oldLayout = this.layout;
    this.layout = val.meta.layout || 'BasicLayout';
    if (oldLayout !== this.layout) {
        const cNode = document.getElementById('SubappViewport');
        this.$nextTick(function () {
          const pNode = document.getElementById('SubappViewportWrapper');
          if (pNode && cNode) {
                pNode.appendChild(cNode);
              }
            });
        }
    }
},
watch: {
    $route (val) {
        this.checkMicroApp(val);
    }
},
mounted () {
    start()
}
})
</script>

<style lang="less">
</style>
  

修改目的,判断路由中是否为微前端模块,如果是的话,就插入微前端模块容器。

然后新建一个qiankun.js文件

js 复制代码
// qiankun.js
import { registerMicroApps, initGlobalState } from 'qiankun';
export const MICRO_APPS = ['test-app']; // 子应用列表
const MICRO_APPS_DOMAIN = '//localhost:8081'; // 子应用入口域名
const MICRO_APP_ROUTE_BASE = '/test-app'; // 子应用匹配规则

const qiankun = {
  install (app) {
     // 加载子应用提示
    const loader = loading => console.log(`加载子应用中:${loading}`);
    const registerMicroAppList = [];
    MICRO_APPS.forEach(item => {
      registerMicroAppList.push({
        name: item,
        entry: `${MICRO_APPS_DOMAIN}`,
        container: '#SubappViewport',
        loader,
        activeRule: `${MICRO_APP_ROUTE_BASE}`
      });
    });
    // 注册微前端应用
    registerMicroApps(registerMicroAppList);

    // 定义全局状态
    const { onGlobalStateChange, setGlobalState } = initGlobalState({
      token: '', // token
    });
    // 监听全局变化
    onGlobalStateChange((value, prev) => {
      console.log(['onGlobalStateChange - master'], value);
    });
  }
};
export default qiankun;

这个文件我们引入了qiankun并对使用它的API进行子应用的注册,之后直接在main.js注册,

js 复制代码
// main.js
...
import qiankun from './qiankun'
Vue.use(qiankun)
...

然后我们只需要对路由做一点点的修改就可以用了

新建RouteView.vue页面,用于接受微前端模块的内容

js 复制代码
//RouteView.vue
 <template>
  <router-view v-slot="{ Component }">
     <component :is="Component" />
  </router-view>
</template>

修改路由配置

js 复制代码
//router.js
const routes = [
  {
    path: '/home',
    name: 'Home',
    meta: {},
    component: () => import('@/views/Home.vue')
  },
  // 当是属于微前端模块的路由, 使用RouteView组件
  {
    path: '/test-app',
    name: 'test-app',
    meta: {},
    component: () => import('@/RouteView.vue')
  }
]

最后就新增一个名为test-app的子应用就可以了。

关于子应用的内容,这次先不说了,码字码累了,下次再说吧。

下集预告(子应用模板编写)

你们肯定会说,不要脸,还搞下集预告。

哼,我只能说,今天周五,准备下班,不码了。🌈

相关推荐
青锐CC24 分钟前
webman使用中间件验证指定的控制器及方法[青锐CC]
中间件·前端框架·php
还是大剑师兰特38 分钟前
D3的竞品有哪些,D3的优势,D3和echarts的对比
前端·javascript·echarts
王解39 分钟前
【深度解析】CSS工程化全攻略(1)
前端·css
一只小白菜~1 小时前
web浏览器环境下使用window.open()打开PDF文件不是预览,而是下载文件?
前端·javascript·pdf·windowopen预览pdf
方才coding1 小时前
1小时构建Vue3知识体系之vue的生命周期函数
前端·javascript·vue.js
阿征学IT1 小时前
vue过滤器初步使用
前端·javascript·vue.js
王哲晓1 小时前
第四十五章 Vue之Vuex模块化创建(module)
前端·javascript·vue.js
丶21361 小时前
【WEB】深入理解 CORS(跨域资源共享):原理、配置与常见问题
前端·架构·web
发现你走远了1 小时前
『VUE』25. 组件事件与v-model(详细图文注释)
前端·javascript·vue.js
Mr.咕咕1 小时前
Django 搭建数据管理web——商品管理
前端·python·django