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

故事的开始

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

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

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

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

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

相关推荐
咬人喵喵20 小时前
CSS Flexbox:拥有魔法的排版盒子
前端·css
LYFlied20 小时前
TS-Loader 源码解析与自定义 Webpack Loader 开发指南
前端·webpack·node.js·编译·打包
yzp011220 小时前
css收集
前端·css
暴富的Tdy20 小时前
【Webpack 的核心应用场景】
前端·webpack·node.js
遇见很ok20 小时前
Web Worker
前端·javascript·vue.js
elangyipi12320 小时前
JavaScript 高级错误处理与 Chrome 调试艺术
开发语言·javascript·chrome
风舞红枫20 小时前
前端可配置权限规则案例
前端
前端不太难21 小时前
RN Navigation vs Vue Router:从架构底层到工程实践的深度对比
javascript·vue.js·架构
zhougl99621 小时前
前端模块化
前端
暴富暴富暴富啦啦啦21 小时前
Map 缓存和拿取
前端·javascript·缓存