一、前言

这篇是记录解决若依vue3版本微应用改造,但是自己之前也试过vue-element-admin框架的微应用改造,前端主流的微应用技术不怎么挑框架的,而且注入方式大同小异。但自己之前尝试的时候踩过很多坑,但是确实比较麻烦,需要耐心研究,但成功的话会提升很多,而且也为之后的开发打好了基础,因此记录下可供大家参考。

二、基座框架

若依vue3版本源码地址:RuoYi-Cloud: 🎉 基于Spring Boot、Spring Cloud & Alibaba的分布式微服务架构权限管理系统,同时提供了 Vue3 的版本

特别注意

  • 若依框架拉下来需要开启后端服务器才可以跑,我是成功跑了以后,再把请求的数据暂时在前端先写成固定的,这样方便调试。请先完成拉下代码成功跑起来这一步再继续看下面哈。
  • 另外安装依赖尽量不要用镜像,yarn 或者 npm install都可以,至于为什么可以看官网。

那么如何改成固定的数据呢?这里有几处的数据需要改一下,请看下面:

1,改造登录方法

由于登录是调用store里面login的方法,这里用到了promise像后端请求,所以需要注掉一些内容;

login方法截图

 token可以复制浏览器网络请求回来的token值:

setToken("eyJhbGciOiJIUzUxMiJ9.eyJsb2dpbl91c2VyX2tleSI6IjJiMjUxZjA3LTc3NjUtNDQ1NC04MWM2LWQ3MDFkYmNmZTNlZiJ9.WtrolkMlQL5-8ZH78niAuNmJo5vsJzu2VJUBT4sopInf4-DP9JMsy_vkVN9pvu4fekZiEuEk1vR3jvU4dki-Nw")

注释掉getInfo方法中以下的代码 

getInfo方法

 注释掉logout方法中以下的代码:

 加上//todo下面的内容:

 this.token = ''
            this.roles = []
            this.permissions = []
            removeToken()
            resolve()
        })

2,改造store/modules/permission.js里面的路由信息

因为原来路由是向后端请求来的,所以我们需要把返回的值直接写死,如下注释掉promise请求的内容。

generateRoutes

 路由信息如下,直接让res等于它即可;

 var res = {
          msg: "操作成功",
          code: 200,
          data: [
            // 首页
            {
              name: "index",
              path: "/index",
              hidden: false,
              redirect: "noRedirect",
              component: "Layout",
              alwaysShow: true,
              meta: {
                title: "首页",
                icon: "fall",
                noCache: false,
                link: null,
              },
              //系统管理
            {
              name: "System",
              path: "/system",
              hidden: false,
              redirect: "noRedirect",
              component: "Layout",
              alwaysShow: true,
              meta: {
                title: "系统管理",
                icon: "fall",
                noCache: false,
                link: null,
              },
              children: [
                {
                  name: "User",
                  path: "user",
                  hidden: false,
                  component: "system/user/index",
                  meta: {
                    title: "用户管理",
                    icon: "user",
                    noCache: false,
                    link: null,
                  },
                },
                {
                  name: "Role",
                  path: "role",
                  hidden: false,
                  component: "system/role/index",
                  meta: {
                    title: "角色管理",
                    icon: "peoples",
                    noCache: false,
                    link: null,
                  },
                },
                {
                  name: "Menu",
                  path: "menu",
                  hidden: false,
                  component: "system/menu/index",
                  meta: {
                    title: "菜单管理",
                    icon: "tree-table",
                    noCache: false,
                    link: null,
                  },
                },
                {
                  name: "Dept",
                  path: "dept",
                  hidden: false,
                  component: "system/dept/index",
                  meta: {
                    title: "部门管理",
                    icon: "tree",
                    noCache: false,
                    link: null,
                  },
                },
                {
                  name: "Post",
                  path: "post",
                  hidden: false,
                  component: "system/post/index",
                  meta: {
                    title: "岗位管理",
                    icon: "post",
                    noCache: false,
                    link: null,
                  },
                },
                {
                  name: "Dict",
                  path: "dict",
                  hidden: false,
                  component: "system/dict/index",
                  meta: {
                    title: "字典管理",
                    icon: "dict",
                    noCache: false,
                    link: null,
                  },
                },
                {
                  name: "Config",
                  path: "config",
                  hidden: false,
                  component: "system/config/index",
                  meta: {
                    title: "参数设置",
                    icon: "edit",
                    noCache: false,
                    link: null,
                  },
                },
                {
                  name: "Notice",
                  path: "notice",
                  hidden: false,
                  component: "system/notice/index",
                  meta: {
                    title: "通知公告",
                    icon: "message",
                    noCache: false,
                    link: null,
                  },
                },
                {
                  name: "Log",
                  path: "log",
                  hidden: false,
                  redirect: "noRedirect",
                  component: "ParentView",
                  alwaysShow: true,
                  meta: {
                    title: "日志管理",
                    icon: "log",
                    noCache: false,
                    link: null,
                  },
                  children: [
                    {
                      name: "Operlog",
                      path: "operlog",
                      hidden: false,
                      component: "monitor/operlog/index",
                      meta: {
                        title: "操作日志",
                        icon: "form",
                        noCache: false,
                        link: null,
                      },
                    },
                    {
                      name: "Logininfor",
                      path: "logininfor",
                      hidden: false,
                      component: "monitor/logininfor/index",
                      meta: {
                        title: "登录日志",
                        icon: "logininfor",
                        noCache: false,
                        link: null,
                      },
                    },
                  ],
                },
              ],
            },
            //系统监控
            {
              name: "Monitor",
              path: "/monitor",
              hidden: false,
              redirect: "noRedirect",
              component: "Layout",
              alwaysShow: true,
              meta: {
                title: "系统监控",
                icon: "fall",
                noCache: false,
                link: null,
              },
              children: [
                {
                  name: "Online",
                  path: "online",
                  hidden: false,
                  component: "monitor/online/index",
                  meta: {
                    title: "在线用户",
                    icon: "online",
                    noCache: false,
                    link: null,
                  },
                },
                {
                  name: "Job",
                  path: "job",
                  hidden: false,
                  component: "monitor/job/index",
                  meta: {
                    title: "定时任务",
                    icon: "job",
                    noCache: false,
                    link: null,
                  },
                },
                {
                  name: "Druid",
                  path: "druid",
                  hidden: false,
                  component: "monitor/druid/index",
                  meta: {
                    title: "数据监控",
                    icon: "druid",
                    noCache: false,
                    link: null,
                  },
                },
                {
                  name: "Server",
                  path: "server",
                  hidden: false,
                  component: "monitor/server/index",
                  meta: {
                    title: "服务监控",
                    icon: "server",
                    noCache: false,
                    link: null,
                  },
                },
                {
                  name: "Cache",
                  path: "cache",
                  hidden: false,
                  component: "monitor/cache/index",
                  meta: {
                    title: "缓存监控",
                    icon: "redis",
                    noCache: false,
                    link: null,
                  },
                },
                {
                  name: "CacheList",
                  path: "cacheList",
                  hidden: false,
                  component: "monitor/cache/list",
                  meta: {
                    title: "缓存列表",
                    icon: "redis-list",
                    noCache: false,
                    link: null,
                  },
                },
              ],
            },
            //系统工具
            {
              name: "Tool",
              path: "/tool",
              hidden: false,
              redirect: "noRedirect",
              component: "Layout",
              alwaysShow: true,
              meta: {
                title: "系统工具",
                icon: "fall",
                noCache: false,
                link: null,
              },
              children: [
                {
                  name: "Build",
                  path: "build",
                  hidden: false,
                  component: "tool/build/index",
                  meta: {
                    title: "表单构建",
                    icon: "build",
                    noCache: false,
                    link: null,
                  },
                },
                {
                  name: "Gen",
                  path: "gen",
                  hidden: false,
                  component: "tool/gen/index",
                  meta: {
                    title: "代码生成",
                    icon: "code",
                    noCache: false,
                    link: null,
                  },
                },
                {
                  name: "Swagger",
                  path: "swagger",
                  hidden: false,
                  component: "tool/swagger/index",
                  meta: {
                    title: "系统接口",
                    icon: "swagger",
                    noCache: false,
                    link: null,
                  },
                },
              ],
            },
            //若依官网
            {
              name: "Http://ruoyi.vip",
              path: "http://ruoyi.vip",
              hidden: false,
              component: "Layout",
              meta: {
                title: "若依官网",
                icon: "guide",
                noCache: false,
                link: "http://ruoyi.vip",
              },
            },
          ],
        };

 3,注释掉登录页的验证码的相关代码

大概步骤如上,可以试试能不能本地启动了,启动后相关页面的表格数据请求不到是正常的。

完成以上的准备工作可以开始微应用注入了。

三、主流微前端框架

1,阿里Qiankun:

官方文档:介绍 - qiankunhttps://qiankun.umijs.org/zh/guideqiankun我踩的坑比较多,所以本篇不涉及,后面单独更新哈;

2,京东MicroApp:

官方文档:MicroAppDescriptionhttps://cangdu.org/micro-app/docs.html#/zh-cn/start(1)主应用

特别注意:主应用路由如果是hash模式,子应用只能是hash模式,主应用如果是history模式,子应用可以是history或者hash模式。

 history: createWebHistory(process.env.BASE_URL)

  • 步骤一:安装依赖

安装依赖:npm i @micro-zoe/micro-app --save 或 yarn add micro-zoe/micro-app --save

  • 步骤二:入口文件引入

// 放在顶部

import microApp from'@micro-zoe/micro-app'

microApp.start()

  • 步骤三:分配个路由给子应用

在store/modules/permission.js的res里面添加一个子应用的路由

            //子应用
            {
              name: "micro",
              path: "/micro-app",
              hidden: false,
              redirect: "noRedirect",
              component: "Layout",
              alwaysShow: true,
              meta: {
                title: "子应用",
                icon: "fall",
                noCache: false,
                link: null,
              },
              children:[
                {
                  name: "micro1",
                  path: "home",
                  hidden: false,
                  component: "micro/micro1/index",
                  meta: {
                    title: "子应用1",
                    icon: "user",
                    noCache: true,
                    link: null,
                  },
                },
                {
                  name:"micro2",
                  path:"about",
                  hidden:false,
                  component:"micro/micro1/index",
                  meta:{
                    title:"子应用2",
                    icon: "user",
                    noCache: true,
                    link: null,
                  }
                }
              ]
            },
  • 步骤四:创建子应用挂载的页面

views文件夹里面新建micro/micro1/index.vue页面

<template>
  <div class="miro-son1">
    <micro-app
      name="micro1" //分配给子应用的children的name
      url="http://localhost:8080/" //子应用跑起来的地址
      baseRoute="/micro-app" //分配子应用的path
      keep-alive //缓存,一定要有
    ></micro-app>
  </div>
</template>

<script>
export default {
  name: "",
  setup() {
    return {};
  },
};
function onBeforeshow(){
  console.log('即将重新渲染,初始化时不执行')
}

</script>

<style scoped lang="scss">
</style>

这个新建的页面不需要自己去挂载app-main里面,不用多此一举的。

(2)子应用

我自己是直接用脚手架创建了vue3的子项目

  • 步骤一:src文件夹下新建public_path.js文件
// __MICRO_APP_ENVIRONMENT__和__MICRO_APP_PUBLIC_PATH__是由micro-app注入的全局变量
if (window.__MICRO_APP_ENVIRONMENT__) {
  // eslint-disable-next-line
  __webpack_public_path__ = window.__MICRO_APP_PUBLIC_PATH__
}
  • 步骤二:main.js引入这个文件,并导出三个方法

import './public_path' // 顶部顶部

// -------------------分割线-umd模式------------------ //
export async function mount(props) {
  // app.createApp(App)
  app.mount(props?.container?.querySelector("#app") || "#app");
  
  console.log("微应用vue2渲染了 -- 来自umd-mount");
}
//卸载应用
export async function unmount() {
  app.destroy();
  app.$el.innerHTML = "";
  app = null;
  console.log("微应用vue2卸载了 -- 来自umd-unmount");
}
export async function bootstrap() {}

// 微前端环境下,注册mount和unmount方法
if (window.__MICRO_APP_ENVIRONMENT__) {
  window[`micro-app-${window.__MICRO_APP_NAME__}`] = { mount, unmount };
} else {
  // 非微前端环境直接渲染
  mount();
}
  • 步骤三: 监听keep-alive状态
// 监听keep-alive模式下的应用状态
window.addEventListener('appstate-change', function (e) {
  if (e.detail.appState === 'afterhidden') {
    console.log('已卸载')
  } else if (e.detail.appState === 'beforeshow') {
    // console.log(routes);
    // console.log(e);
    
    console.log('即将重新渲染')
    const baseRoute = window.__MICRO_APP_BASE_ROUTE__ ;
    const p = window.location.pathname;
      const paramsBeginIndex = p.indexOf("?");
      const path = p.substring(baseRoute.length, paramsBeginIndex === -1 ? undefined : paramsBeginIndex);
      // const query = convertHrefSearch(window.location.search);
      console.log(baseRoute);
      console.log(path);
      
      
      //todo
      if (routes) {
        if (path) {
          // if (path === "home") {
          //   window.$router.replace({ path: "/", query });
          // }
          var completePath = baseRoute+path;
          console.log(completePath);
          routes.replace({ path:completePath });
        }
      } else console.warn("[MicroAppSetup]: 没有发现window.$router路由对象");
  } else if (e.detail.appState === 'aftershow') {
    console.log('已经重新渲染')
  }
})
  • 步骤四:子应用配置跨域
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
  transpileDependencies: true,
  devServer: {
    port: 8080,                             // 修改端口
    headers: {
      'Access-Control-Allow-Origin': '*',   // 设置跨域
    },
  }
})

好了,差不多可以跑了,耐心的调试会成功的,当然关于如何父子应用通信这篇就不说了,可以参考官方文档,后面自己尝试了后再更新。

另外,如果真的诚心想啃下微前端这块硬骨头的话,大家可以加一下官网的微信群,我就是keep-alive的问题出现了问题,求教大佬,慢慢研究出来的。加油!

Logo

快速构建 Web 应用程序

更多推荐