微前端 qiankun 框架接入问题记录

背景:需要搭建一个平台,这个平台的主要功能是集成各个子系统,方面对系统之间的统一管理。在搭建这样一个平台时,前端考虑使用微前端架构方式实现,使用的框架是 qiankun,本文主要记录在 qiankun 框架使用过程中遇到的问题,及解决方法。

问题一:本地联调时报跨域问题及子应用无法 fetch 到,如下:

解决方法,修改主应用的配置,如下:

问题二:主应用可以连接到子应用,但在主应用中未显示子应用,如下:

解决方法,修改主应用的配置,如下:

主应用中未提供子应用需要挂载的 dom 元素

问题三:vue-router3 路由重复点击页面报错,如图:

解决方法,在 router 路由文件中修改 push replace 方法:

import Vue from 'vue';
import VueRouter from 'vue-router';
import HomeView from '../views/HomeView.vue';
import AboutView from '../views/AboutView.vue';
import MicroApp from '../components/MicroApp.vue';Vue.use(VueRouter);const { isNavigationFailure, NavigationFailureType } = VueRouter;
const originalPush = VueRouter.prototype.push;
VueRouter.prototype.push = function push(location) {return originalPush.call(this, location).catch((failure) => {if (isNavigationFailure(failure, NavigationFailureType.aborted)) {throw failure;}});
};const originalReplace = VueRouter.prototype.replace;
VueRouter.prototype.replace = function replace(location) {return originalReplace.call(this, location).catch((failure) => {if (isNavigationFailure(failure, NavigationFailureType.aborted)) {throw failure;}});
};const routes = [{path: '/',name: 'home',component: HomeView,},{path: '/about',name: 'about',component: AboutView,},{path: '/child-app1',component: MicroApp,},
];const router = new VueRouter({mode: 'history',routes,
});export default router;

问题四:主应用加载子应用之后,子应用内的路由跳转失败,如图:

解决方法,在路由文件中修改加载子应用的路由,并在修改主应用中的路由跳转方法,如图:

参考链接:导航故障 | Vue Router

qiankun 接入时的前期问题,大多是配置错误,主应用和子应用 name 对应不上,或者主应用未给子应用提供容器标签等,主要参考链接:

常见问题 - qiankun

简单总结:

1、主应用配置

主应用挂载组件:/component/Micro.vue

安装 qiankun

$ yarn add qiankun # 或者 npm i qiankun -S
document.subApps = [{name: 'childApp1',entry: '//localhost:8081/child-app1/',container: '#container-child-app1',activeRule: '/child-app1',},
];
<template><div id="container-child-app1"></div>
</template><script>
import { loadMicroApp } from 'qiankun';
import actions from '../../actions.js';export default {name: 'microApp',mixins: [actions],data() {return {microApp: null,};},mounted() {const getMicroInfo = this.getMicroInfo();this.microApp = loadMicroApp(getMicroInfo, { singular: true });},beforeDestroy() {this.microApp.unmount();},methods: {// 手动加载微应用getMicroInfo() {const appIdentifying = this.$route.path.split('/')[1];let data = {};const href = window.location.host;for (let i = 0; i < document.subApps.length; i++) {const element = document.subApps[i];if (element.activeRule.includes(appIdentifying)) {if (typeof element.entry !== 'string') {data = {...element,entry: element.entry[href]? element.entry[href]: Object.values(element.entry)[0],};} else {data = { ...element };}data.props = {token: {userInfo: {userName: '小明',userId: '123',date: new Date().toLocaleString(),},},};data.activeRule = [appIdentifying];break;}}console.log('data::', data);return data;},},
};
</script>

 组应用挂载子应用的路由修改:

import Vue from 'vue';
import VueRouter from 'vue-router';
import HomeView from '../views/HomeView.vue';
import AboutView from '../views/AboutView.vue';
import MicroApp from '../components/MicroApp.vue';Vue.use(VueRouter);const { isNavigationFailure, NavigationFailureType } = VueRouter;
const originalPush = VueRouter.prototype.push;
VueRouter.prototype.push = function push(location) {return originalPush.call(this, location).catch((failure) => {if (isNavigationFailure(failure, NavigationFailureType.aborted)) {throw failure;}});
};const originalReplace = VueRouter.prototype.replace;
VueRouter.prototype.replace = function replace(location) {return originalReplace.call(this, location).catch((failure) => {if (isNavigationFailure(failure, NavigationFailureType.aborted)) {throw failure;}});
};const routes = [{path: '/',name: 'home',component: HomeView,},{path: '/about',name: 'about',component: AboutView,},{// 子应用路由path: '/child-app1',component: MicroApp,},
];const router = new VueRouter({mode: 'history',routes,
});export default router;

App.vue 可以指定子应用容器位置:

<template><div id="app"><container-main><el-breadcrumb separator-class="el-icon-arrow-right"><el-breadcrumb-item><el-button type="text" @click="handleJumpParentHome">主应用 home</el-button></el-breadcrumb-item><el-breadcrumb-item><el-button type="text" @click="handleJumpParentAbout">主应用 about</el-button></el-breadcrumb-item><el-breadcrumb-item><el-button type="text" @click="handleJumpChildApp1">子应用 home</el-button></el-breadcrumb-item></el-breadcrumb><!-- 可以不写,写了之后未指定了子应用挂载位置 --><div id="container-child-app1"></div></container-main><router-view /></div>
</template><script>
import ContainerMain from './components/ContainerMain.vue';export default {name: 'App',components: {ContainerMain,},data() {return {};},methods: {handleJumpParentHome() {this.$router.push({path: '/',});},handleJumpParentAbout() {this.$router.push({path: '/about',});},handleJumpChildApp1() {this.$router.push({path: '/child-app1',});},},
};
</script><style>
#app {font-family: Avenir, Helvetica, Arial, sans-serif;-webkit-font-smoothing: antialiased;-moz-osx-font-smoothing: grayscale;text-align: center;color: #2c3e50;
}
</style>

2、子应用配置

main.js 中配置:

import Vue from 'vue';
import App from './App.vue';
import routes from './router';
import VueRouter from 'vue-router';
import store from './store';
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';Vue.config.productionTip = false;
Vue.use(ElementUI);if (window.__POWERED_BY_QIANKUN__) {/* eslint-disable @typescript-eslint/camelcase */__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}let router = null;
let instance = null;
function render(props = {}) {console.log('子应用 render props::', props, 'instance====', instance);// sessionStorage.setItem('userInfo', JSON.stringify(props.token.userInfo));const { container } = props;router = new VueRouter({base: window.__POWERED_BY_QIANKUN__ ? '/child-app1/' : '/',mode: 'history',routes});instance = new Vue({router,store,render: (h) => h(App)}).$mount(container ? container.querySelector('#app') : '#app');
}// 独立运行时
/* eslint-disable */
if (!window.__POWERED_BY_QIANKUN__) {render();
}export async function bootstrap() {console.log('子应用 bootstrap ===========================');
}let initialState = null;
export async function mount(props) {console.log('子应用 mount props ===============', props);sessionStorage.setItem('userInfo', JSON.stringify(props.token.userInfo));props.onGlobalStateChange((state, prev) => {// state: 变更后的状态; prev 变更前的状态console.log('子应用获取共享数据 state::', state, 'prev::', prev);// 接收主应用中的共享数据 并将其设置为全局变量Vue.prototype.$initialState = state;});props.setGlobalState({initialState:'子应用中修改主应用中的全局变量,实现住应用子应用间数据的双向双向通信'});render(props);
}
export async function unmount() {console.log('子应用 unmount==========');instance.$destroy();instance.$el.innerHTML = '';instance = null;router = null;
}

子应用中的打包配置修改:

const { defineConfig } = require('@vue/cli-service');module.exports = defineConfig({transpileDependencies: true,publicPath: '/child-app1/',devServer: {headers: {'Access-Control-Allow-Origin': '*'}},configureWebpack: {output: {/**{name: 'childApp1',entry: '//localhost:8081/child-app1/',container: '#container-child-app1',activeRule: '/child-app1',},library 与 主应用中的 name 保持一致**/library: `childApp1`,libraryTarget: 'umd', // 把微应用打包成 umd 库格式chunkLoadingGlobal: `webpackJsonp_childApp1` // webpack 5 需要把 jsonpFunction 替换成 chunkLoadingGlobal}}
});

代码上传到了 github 上,后序会持续更新代码。

GitHub - 13523010484/qiankun-vue

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/823402.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Leetcode每日一题】 分治 - 颜色分类(难度⭐⭐)(57)

1. 题目解析 题目链接&#xff1a;75. 颜色分类 这个问题的理解其实相当简单&#xff0c;只需看一下示例&#xff0c;基本就能明白其含义了。 2.算法原理 算法思路解析 本算法采用三指针法&#xff0c;将数组划分为三个区域&#xff0c;分别用于存放值为0、1和2的元素。通过…

Ubuntu修改DNS

【永久修改DNS】 临时修改DNS的方法是在 /etc/resolv.conf 添加&#xff1a;nameserver 8.8.8.8 nameserver 8.8.8.8 注意到/etc/resolv.conf最上面有这么一行&#xff1a; DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTEN 说明重启之后这个文件会被自动…

CTFHUB-技能树-Web前置技能-文件上传(无验证,JS前端验证,前端验证)

CTFHUB-技能树-Web前置技能-文件上传&#xff08;无验证&#xff0c;JS前端验证&#xff0c;前端验证—.htaccess&#xff09; 文章目录 CTFHUB-技能树-Web前置技能-文件上传&#xff08;无验证&#xff0c;JS前端验证&#xff0c;前端验证—.htaccess&#xff09;文件上传无验…

【在线OJ系统】自定义注解实现自增ID的无感插入

实现思路 首先自定义参数注解&#xff0c;然后根据AOP思想&#xff0c;找到该注解作用的切点&#xff0c;也就是mapper层对于mapper层的接口在执行前都会执行该aop操作&#xff1a;获取到对于的方法对象&#xff0c;根据方法对象获取参数列表&#xff0c;根据参数列表判断某个…

电商数据采集的网页抓取数据、淘宝、天猫、京东等平台的电商数据抓取|电商数据API接口网页爬虫、采集网站数据

电商数据采集的网页抓取数据、淘宝、天猫、京东等平台的电商数据抓取&#xff0c;网页爬虫、采集网站数据、网页数据采集软件、python爬虫、HTM网页提取、APP数据抓包、APP数据采集、一站式网站采集技术、BI数据的数据分析、数据标注等成为大数据发展中的热门技术关键词。那么电…

深入理解同步与异步编程及协程管理在Python中的应用

文章目录 1. 同步与异步函数的对比1.1 同步函数1.2 异步函数1.3 对比 2. 管理多个协程与异常处理2.1 并发执行多个协程2.2 错误处理2.3 任务取消 本文将探索Python中同步与异步编程的基本概念及其区别。还会详细介绍如何使用asyncio库来有效管理协程&#xff0c;包括任务的创建…

最新的网易星球GEC挖矿系统修复版 章鱼星球挖矿系统源码 区块链虚拟币交易源码 基于ThinkPHP5开发

区块链系统介绍 2018.12.10更新增加聚合数据短信接口 2018.11.19更新增加短信宝接口 2018.08.17修复Linux系统搭建验证码不显示问题 2018.08.09修复后台某处溢出数据库账号密码BUG 2018.08.06修复票卷BUG 源码介绍&#xff1a; 区块链系统中用户共九个等级&#xff0c;依…

旧衣服回收小程序,旧衣回收行业的必然发展趋势

近年来&#xff0c;旧衣回收行业成为了一个新型的创业项目&#xff0c;因其投资成本低、回报高的优势&#xff0c;也成为了当下年轻人的创业新选择。 一、旧衣服回收市场发展趋势 当下人们对衣物淘汰的速度逐渐加快&#xff0c;每年产生的废旧衣物高达百万吨&#xff0c;加之…

.cur 鼠标光标编辑器

详解透明贴图和三元光栅操作 - CodeBus 鼠标指针文件格式解析——Windows&#xff08;二&#xff09; (qq.com) [C/C] RGBA数组生成Windows下的ico文件_c ico格式-CSDN博客 色环设计 - CodeBus 左键绘制 右键选颜色 ctrl右键设置鼠标热点 F1导出.cur文件 //代码来源&…

【考研高数】学习笔记分享

派大星说数学&#xff08;导学部分&#xff09; 关于做题 测试 答疑阶段 直播 群内 高中基础知识导学 一、数与式 述了课程学习和因式分解、分式拆解等知识点。学生应了解课程内容&#xff0c;带着疑问听课&#xff0c;不要抄笔记&#xff0c;导学课和基础课都有测验&…

Zabbix监控Windows

1.在虚拟机中安装zabbix 安装系统一直托不进虚拟机中&#xff1b;因为没安装Tools组件 点击虚拟机&#xff0c;选择安装VMware Tools 2.配置zabbix

荣誉 | 人大金仓获评轨交行业“智慧运维优秀应用案例”

4月12日至13日&#xff0c;2024&#xff08;第八届&#xff09;中国城市轨道交通智慧运维大会在成都顺利举行。会上&#xff0c;人大金仓以其在轨交行业的卓越贡献和创新实践&#xff0c;获评“智慧运维优秀应用案例”。公司副总裁梁红凤出席大会并发表了题为“打造世界一流的数…

顺序表(增删减改)+通讯录项目(数据结构)+顺序表专用题型

什么是顺序表 顺序表和数组的区别 顺序表本质就是数组 结构体初阶进阶 系统化的学习-CSDN博客 简单解释一下&#xff0c;就像大家去吃饭&#xff0c;然后左边是苍蝇馆子&#xff0c;右边是修饰过的苍蝇馆子&#xff0c;但是那个好看的苍蝇馆子一看&#xff0c;这不行啊&a…

EcoVadis评估是什么?EcoVadis评估的步骤有哪些

EcoVadis评估是一种针对供应链中各个环节的环境和社会责任进行评估的工具。其评估范围广泛&#xff0c;涵盖了环境、劳工与人权、商业道德和可持续采购等多个领域。通过收集企业的公开信息、企业提供的数据和自我评估问卷等方式&#xff0c;EcoVadis能够为企业提供一个全面的可…

【智能排班系统】Quartz结合Cron-Utils自定义时间发送上班、休息提醒

文章目录 Quartz&#xff1a;强大的Java作业调度引擎Quartz概述核心概念与架构配置文件主配置&#xff08;配置主要调度器设置、事务&#xff09;线程池配置&#xff08;调整作业执行资源&#xff09;SimpleThreadPool特定属性自定义线程池 RAMJobStore配置&#xff08;在内存中…

域名网络、

http://www.localhost:8080/hello http://127.0.0.1:8080/hello 一般在本机的C:\Windows\System32\drivers\etc的host文件里都有 在这个hosts配置文件中有一个127.0.0.1和默认的用户名locahost&#xff0c;在tomcat启动后输入的地址就是localhost端口号&#xff0c;默认的…

【文献分享】PCCP:机器学习 + 分子动力学 + 第一性原理 + 热学性质 + 微观结构

分享一篇关于机器学习 分子动力学 第一性原理 热学性质&#xff08;密度、粘度、扩散系数&#xff09; 微观结构的文章。 感谢论文的原作者&#xff01; 关键词&#xff1a; 1. Machine learning, 2. Deep potential, 3. Molecular dynamics 4. Molten salt, 5. Thermo…

【系统分析师】系统安全分析与设计

文章目录 1、安全基础技术1.1 密码相关1.1.1对称加密1.1.2非对称加密1.1.3信息摘要1.1.4数字签名1.1.5数字信封 1.2 PKI公钥体系 2、信息系统安全2.1 保障层次2.2 网络安全2.2.1WIFI2.2.2 网络威胁与攻击2.2.3 安全保护等级 2.3计算机病毒与木马2.4安全防范体系 1、安全基础技术…

游戏生成式 AI:编织梦想,避开阴影

想象一下&#xff0c;一个沉浸式的游戏世界中玩家遇到的每个 NPC 都由 AI 驱动&#xff0c;他们能与玩家进行互动&#xff0c;从改变游戏体验。据 Inword 一项研究显示&#xff0c;绝大多数游戏玩家渴望这种互动&#xff0c;愿意投入更多的时间和金钱来玩这种由 AI 驱动的游戏。…

第十三章 使用深度和法线纹理

获取深度和法线纹理 背后的原理 深度纹理是一张渲染纹理,它里面存储的像素值不是颜色,而是一个高精度的深度值。深度值范围是[0, 1],非线性分布的。这些深度值来自于顶点变换后得到的归一化的设备坐标(NDC)。一个模型想要被绘制在屏幕上,需要把它的顶点从模型空间变换到齐…