目录

  • 前言
  • 主应用
  • 微应用
  • 部署

前言

因为业务系统接入的需要,决定将一个vue3+vite+ts的主应用系统,改造成基于qiankun的微应用架构。此文记录了改造的过程及vue3微应用接入的种种问题。

网上有很多关于微应用改造的案例,但很多都没写部署之后什么情况。写了部署的,没有实操部署在二级目录、三级目录是什么情况,甚至没有对部署之后的情况做测试、没有说明。这是在整个改造过程中最难的一点,也是最困扰我的一个问题。我们所改造的应用说明:

  • 主应用:vue3+vite+ts
  • 微应用1:vue2,qiankun官网API是基于vue2+webpack,我们对vue2也进行了接入,但是在本篇文章中不做说明。
  • 微应用2:vue3+vite,由于主应用已经是vue3的系统,所以,微应用也决定直接使用vue3框架

不懂的地方可以参考qiankun官方API,本文记录的是 基于vue3+vite的微应用,如何在vue3+vite的主应用中接入,以及完整的改造过程。首先有三个前提条件:

  • 主应用为经典运营系统的左右布局结构(下图),要求将微应用接入为主应用的一个路由页面
  • 微应用和主应用部署在不同的服务;
  • 主应用部署在二级目录。

图中所示的微应用菜单处,就是可以动态插拔微应用的菜单。

主应用

  1. 在主应用中注册微应用路由
const microRouters = [{path: '/vite-vue3-app2/', // path值必须与微应用中,路由前缀的`${parentBase}${packagejson.name}`中的${packagejson.name}值相同,否则访问会出错,${parentBase}为主应用部署的目录路径,后面内容中会讲component: Layout,name: 'vite-vue3-app2',meta: { title: '微应用测试2', icon: 'dashboard' },children: [ // 想要显示的微应用路由,都需要在主应用中注册{path: 'hello',component: () => import('@/views/Portal.vue'), // 所有路由都使用同一个vue组件hidden: false,name: 'app2-hello',meta: { title: 'app2-hello', icon: 'dashboard' }},{path: 'home',component: () => import('@/views/Portal.vue'),hidden: false,name: 'app2-home',meta: { title: 'app2-home', icon: 'dashboard' }},{path: 'about',component: () => import('@/views/Portal.vue'),hidden: false,name: 'app2-about',meta: { title: 'app2-about', icon: 'dashboard' }},]},
]
  1. 注册微应用
registerMicroApps([{name: 'app2',entry: '/app2/', // entry,访问时,主应用的路径中会带有/app2/,通过niginx代理进入微应用container: '#view-main',activeRule: location => {return location.pathname.includes('/vite-vue3-app2') // 路由中包含/vite-vue3-app时,激活该微应用},props: {agg: '/vite-vue3-app2',// 注意:_parent_base是主应用的路由前缀(可以使用变量),在微应用启动时会使用到(!!!重点)_parent_base: '/portal/admin-console/'}}

注册微应用阶段,需要注意的事项:

    1. entry使用一个字符串'/app2/',在服务配置中通过nginx代理转发到微应用;
    1. 注册微应用时,传递参数_parent_base,这是主应用部署的二级目录,在微应用不独立运行时,路由需要携带该参数一起。
    1. 父级路由的path: '/vite-vue3-app2/',必须与微应用中的路由前缀${parentBase}${packagejson.name}${packagejson.name}的值相同,否则访问会出错。(${parentBase}是主应用部署的目录路径,后面内容中会讲)
  1. 注册Portal.vue组件,并在组件 mounted 中调用start函数
<template><div id="view-main" class="sub-app-container"></div>
</template><script lang="ts" setup>
import { onMounted } from 'vue';
import { start } from 'qiankun'onMounted(() => {if(!(window as any).qiankunStarted) {(window as any).qiankunStarted = truestart({ sandbox: { experimentalStyleIsolation: true, singular: false } });}
})
</script>

微应用

因为qiankun目前还没有支持vue3使用,官方API中的方法行不通,可以使用有大佬开发的vite-plugin-qiankun插件。首先在微应用中安装插件:vite-plugin-qiankun,然后按照如下方法修改:

1.main.js文件修改

import { createApp } from 'vue' // vue3引入
import Cookies from 'js-cookie'
import ElementPlus from 'element-plus' // 引入element-plus
import locale from 'element-plus/lib/locale/lang/zh-cn' // 中文语言import '@/assets/styles/index.scss' // global cssimport App from './App'
import store from './store' //store/*** 这里需要特别注意:我们将router定义为了一个函数。* 因为主应用部署在二级目录,当微应用不独立运行时,如果微应用的router没有带上主应用二级目录作为前缀,访问会出错,具体原因下面介绍*/
import { router } from './router' // routerimport plugins from './plugins' // plugins
import { renderWithQiankun, qiankunWindow } from 'vite-plugin-qiankun/dist/helper'let app = null
// 独立运行时
if(!qiankunWindow.__POWERED_BY_QIANKUN__) {app = createApp(App)app.use(router('')).use(store).use(plugins) // router(''),独立运行,路由前缀为空app.use(ElementPlus, {locale: locale,size: Cookies.get('size') || 'default'})app.mount('#app')
} else {// 作为微应用运行renderWithQiankun({ // 调用renderWithQiankunmount(props) {app = createApp(App)app.use(router(props._parent_base))// 路由前缀添加router(props._parent_base),_parent_base是从主应用中传过来的.use(store).use(plugins) app.use(ElementPlus, {locale: locale,size: Cookies.get('size') || 'default'})app.mount(props.container ? props.container.querySelector('#app') : '#app')},bootstrap() {console.log('-- bootstrap --')},update() {console.log('-- update --')},unmount() {console.log('-- unmount --', app)app?.unmount()}})
}

当微应用不独立运行时,为什么路由前缀中要加上主应用的部署目录?

  • 首先,主应用不是部署在服务器的根目录,而是在/portal/admin-console/目录下。所以,访问该应用的任何一个页面,都需要加上该目录作为访问地址,如系统的home页,就需要这样访问:http://localhost:18080/portal/admin-console/index,index是路由,前面是服务域名+目录。
  • 其次,假设微应用的路由不加如上所讲的目录作为前缀,会怎么样呢?这是当时部署后遇到的一个最大的难题。

如上图所示,我们访问了vite-vue3-app2/hello这个路由,而在点击后却跳转到了http://localhost:8082/vite-vue3-app2/portal/admin-console/vite-vue3-app2/hello,页面404错误。对比之下就会发现,qiankun在调起微应用时,将微应用的路由前缀添加在了主应用的域名后面,我们之所以在主应用中添加与微应用前缀一致的路由名称,也是因为这个原因。

当访问以上页面时,访问的域名是http://localhost:8082,所以原本微应用中的路由前缀就会添加在8082后面,而不是添加在/portal/admin-console/后面。

而当我们按照如上所讲的,将微应用中的路由前缀改为${parentBase}${packagejson.name}时(请参考如下2.微应用路由定义),访问就会变的正常。如果主应用部署在根目录,则parenBase给空值。

这一点对于部署在非根目录的服务非常重要,但在官方API中没有说明。是在开发环境调试正常,部署之后遇到的巨坑。

  1. 微应用路由定义:router.js文件
import { createWebHistory, createRouter } from 'vue-router'
import { qiankunWindow } from 'vite-plugin-qiankun/dist/helper'export const constantRoutes = [{path: '/home',component: () => import('@/views/micro/home.vue'),hidden: true},{path: '/hello',component: () => import('@/views/micro/hello.vue'),hidden: true},{path: '/about',component: () => import('@/views/micro/about.vue'),hidden: true},
];const router = (parentBase) => {/*** 区别作为微应用运行和独立运行时的路由base* 1. 当作为微应用运行时:路由前缀为 ${parentBase}${packagejson.name}`*      - parentBase是从主应用中传过来的参数*      - packagejson.name是在package.json文件中定义的固定变量,是为了方便使用和便于区分,这个应该大家都能够理解* 2. 独立运行时:路由前缀为/app2*/const base = qiankunWindow.__POWERED_BY_QIANKUN__ ? `${parentBase}${packagejson.name}` : '/app2'return createRouter({history: createWebHistory(base),routes: constantRoutes,scrollBehavior(to, from, savedPosition) {if (savedPosition) {return savedPosition} else {return { top: 0 }}},});
}export { router }
  1. vite.config.js文件修改
import { defineConfig, loadEnv } from 'vite'
import path from 'path'
import createVitePlugins from './vite/plugins'export default defineConfig(({ mode, command }) => {const env = loadEnv(mode, process.cwd())const { VITE_APP_ENV, VITE_WEB_APP_DIR } = envreturn {configureWebpack: { // webpack 配置devtool: 'source-map',},/*** 代理的问题:微应用打包的 base 必须跟主应用中的代理地址 entry 值一致* 但是,加上 /app2/ 之后,就必须部署在 app2 目录,否则无法独立访问。*/base: '/app2/',build: {assetsDir: "assets",},plugins: createVitePlugins(env, command === 'build'),resolve: {alias: {'~': path.resolve(__dirname, './'),'@': path.resolve(__dirname, './src')},extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue']},server: { ... }, // server配置省略}
})

vite.config.js中的配置,主要是修改base值,如代码片段中的注释:

  • 微应用打包的 base必须跟主应用中的代理地址 entry 值一致。
  • 微应用必须部署在base 目录,否则无法独立访问。
  1. package.json文件修改
    package.json 文件中主要是修改了name值,这是为了方便在router中使用,全局使用统一的变量值更便于理解。你也可以自己选择修改或不修改,这里的值改动,不会影响整体功能的运行

部署

  1. 主应用部署

主应用部署在\portal\admin-console目录下,如下图所示nginx服务目录结构:

nginx配置:

server {listen       18080;server_name  localhost;......其它内容省略location /portal/admin-console/ {root app;index index.html;// 主应用是history模式,解决404问题try_files $uri $uri/ /portal/admin-console/index.html;}// 后端服务的代理location /dev-api/ {proxy_pass https://xxxxxxxxxxx/;}// 微应用代理location /app2/ {proxy_pass http://localhost:18089/app2/; // 微应用部署的服务}error_page   500 502 503 504  /50x.html;location = /50x.html {root   html;}}
  1. 微应用部署
    如前所示,微应用需要部署在/app2目录下,微应用的静态文件路径:

    nginx配置:
server {listen       18089;server_name  localhost;// ......其它内容省略location /app2/ {root app;index index.html;// 404try_files $uri $uri/ /app2/index.html;}error_page   500 502 503 504  /50x.html;location = /50x.html {root   html;}}

至此,qiankun微应用接入成功。主应用、微应用单独访问或在主应用中访问微应用,都能够正常访问。

在改造的过程中,遇到了两个难题:

  1. entry微应用的入口。官方只给出了很多个方案,但都没有我想要的:在菜单中添加微应用,还要通过代理来激活。这个问题的解决都还相对容易,比较难搞的是下面一个问题。
  2. 主应用部署在了非根目录下,出现如上所述访问跳转错误的问题。这个问题的解决只能通过不断观察,观察每次路由访问时出现错误的情况,一步一步逐层破解,直到最后发现解决问题的办法。实际上,问题的最终解决看似很简单,但是破解问题的过程并不容易。参考官方API将每一步都测试没有问题了,但我的问题就是存在,翻遍搜索引擎也没有找到我想要的答案,只能自己一步一步破解。解决问题的过程很难熬,但解决之后的成就感也是满满的!

所以,遇到问题 还是可以多探索探索的呀!!!

07. vue3+vite+qiankun搭建微应用前端框架,并接入vue3微应用相关推荐

  1. 【几乎最全/全网最长的 2 万 字】前端工程化完整流程:从头搭到尾(vue3 + vite + qiankun + docker + tailwindcss + iview......)

    文章目录 一.完整构建流程 1.在指定目录下执行 pnpm init,初始化 package.json 2.执行 pnpm install vite -D,安装 vite. 3.package.jso ...

  2. vue3+vite环境搭建 vue3+vite实战

    目录 1.安装 vue-cli 3 2.安装vite 3.安装成功后**package.json**中会添加 4.通过@vitejs/plugin-vue插件来支持Vue 5.安装路由 6.在入口文件 ...

  3. 从零开始搭建一个项目-前端框架(vue)

    基础框架:Vue UI框架:iview 样式:less 用到模块:vuex vue-router Ajax:anios 第一步 安装淘宝镜像代替npm(可省略,如果省略了,后面所有cnpm改为npm) ...

  4. 酷我音乐盒java_Java Swing仿“酷我音乐盒”界面,搭建简单通用前端框架

    使用Java的Swing技术也可以做出很炫的界面,不过效率貌似不是很好,但是在现如今机子配置都超高的情况下,其应该是可以被接受的.. 程序截图如下: 部分代码如下: /** * */ package ...

  5. 使用vue3 +vite + typeScript + elementPlus搭建一个项目脚手架

    使用vue3 + vite + elementPlus搭建一个项目脚手架 这篇文章就教大家如何使用vue3+vite+ts+element-plus搭建一个项目,步骤详细,献给不爱看文档的诸位,希望这 ...

  6. 基于京东micro-app微前端框架的项目实践

    1.微前端应用介绍 1.1.微前端概念 微前端的概念是由ThoughtWorks在2016年提出的,它借鉴了微服务的架构理念,核心在于将一个庞大的前端应用拆分成多个独立灵活的小型应用,每个应用都可以独 ...

  7. 极简微前端框架-京东MicroApp开源了

    前言 MicroApp是一款基于类WebComponent进行渲染的微前端框架,不同于目前流行的开源框架,它从组件化的思维实现微前端,旨在降低上手难度.提升工作效率.它是目前市面上接入微前端成本最低的 ...

  8. Vue+Iview前端框架搭建

    Vue+Iview前端框架搭建 前端搭建 插件介绍 引入到项目 前端搭建 Vue+Iview前端框架需要的插件 插件介绍 Vue,Iview,常用的v-charts Vue.js , 点我到官网.笔者 ...

  9. vue3 + vite + ts 集成mars3d

    vue3 + vite + ts 集成mars3d 文章目录 vue3 + vite + ts 集成mars3d 前言 一.创建一个vue3 + vite + ts项目 二.引入mars3d相关依赖 ...

最新文章

  1. Django2.0——模板渲染(一)
  2. DataGridView的DataGridViewComboBoxColumn列点击一次,自动处于编辑状态
  3. (转)linux内核虚拟文件系统浅析
  4. Uboot启动流程分析
  5. python 将ipv4的格式转换
  6. 浮点与定点的二进制存储
  7. html 手机a标签点不动,htmlunit单击javascript a标签不起作用
  8. 大牛书单 | 新年聊创新:技术人必备思维
  9. jboss相关的术语
  10. 设计模式 C++单例模式
  11. 基于NSString处理文件的高级类
  12. vue-cli3项目中全局引入less sass文件 以及使用本地图片在不同地方规则
  13. Quartus II破解出现的问题
  14. 维基百科英文语料库下载地址
  15. 服务器lsass系统错误,急急急开机出现lsass.exe系统错误系统资源不够无法完成AP? 爱问知识人...
  16. QT 使用QAxWidget和QAxObject操作DOCX和EXECL文件,包括修改数据、插入图片、修改表格、打印文档、复制SHEET、修改页码数等
  17. w10系统的服务器属性在哪,DNS设置在哪里、设置什么好?Win10电脑DNS设置指南
  18. 江南春新年围炉夜谈:如何破解增长焦虑?
  19. 从软件架构演变看运维的分工与融合
  20. Learning Center Probability Map for Detecting Objects in Aerial Images 论文学习笔记

热门文章

  1. 2021年起重机械指挥考试题库及起重机械指挥考试技巧
  2. unsafe原理 java_Unsafe原理
  3. 零基础入门语义分割-地表建筑物识别 Task2 数据扩增 -学习笔记
  4. 判断素数的高效的方法
  5. ycrcb各分量含义_YCrCb与YPrPb的含义与区别
  6. Conda——加载本地环境
  7. Manacher(马拉车)算法—简略讲解
  8. C语言中的所有运算符用法及总结
  9. 关爱儿童成长:培养儿童专注力书单(组图
  10. 基于深度学习的目标检测综述(一):简介及骨干网络