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

故事的开始

在一个风和日丽的下午,我正喝着女神请的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的子应用就可以了。

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

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

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

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

相关推荐
用户761736354012 分钟前
CSS重点知识-样式计算
前端
yoyoma4 分钟前
object 、 map 、weakmap区别
前端·javascript
shyshi6 分钟前
vercel 部署 node 服务和解决 vercel 不可访问的问题
前端·javascript
.生产的驴6 分钟前
React 模块化Axios封装请求 统一响应格式 请求统一处理
前端·javascript·react.js·前端框架·json·ecmascript·html5
前端大神之路7 分钟前
vue2 响应式原理
前端
一个努力的小码农7 分钟前
Rust中if let与while let语法糖的工程哲学
前端·rust
雾岛听风来9 分钟前
Android开发中常用高效数据结构
前端·javascript·后端
IT_陈寒9 分钟前
Vue 3性能优化实战:这5个Composition API技巧让你的应用快30%
前端·人工智能·后端
IT_陈寒17 分钟前
Vue3性能翻倍的5个秘密:从Composition API到Tree Shaking实战指南
前端·人工智能·后端
IT_陈寒30 分钟前
JavaScript 性能优化:3个V8引擎隐藏技巧让你的代码提速50%
前端·人工智能·后端