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

news2025/3/1 6:29:47

背景:需要搭建一个平台,这个平台的主要功能是集成各个子系统,方面对系统之间的统一管理。在搭建这样一个平台时,前端考虑使用微前端架构方式实现,使用的框架是 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.coloradmin.cn/o/1601334.html

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

相关文章

PDF文档电子签名怎么做?

如何确保电子文档的签署具有公信力和法律效力&#xff0c;防止伪造和假冒签名等问题&#xff0c;是电子文档无纸化应用面临的重要挑战。本文将详细介绍PDF文档电子签名的概念、重要性、实施步骤以及相关的法律背景&#xff0c;帮助用户理解并有效应用PDF文档电子签名技术。 1.…

【学习笔记】Python大数据处理与分析——Matplotlib数据可视化

一、绘图步骤 1、导入第三方库 import matplotlib.pyplot as plt import numpy as np 2、准备数据 x1 np.linspace(1, 10, 5) y1 np.sin(x1) 3、开始绘图 plt.plot(x1, y1, linewidth3) 4、完善图表 plt.title("plot figure") plt.xlabel("value of x&qu…

个人网站制作 Part 22 添加页面缓存 | Web开发项目添加页面缓存

文章目录 &#x1f469;‍&#x1f4bb; 基础Web开发练手项目系列&#xff1a;个人网站制作&#x1f680; 添加页面缓存&#x1f528;使用浏览器缓存&#x1f527;步骤 1: 设置响应头步骤 2: 使用ETag &#x1f528;使用 Vue.js&#x1f527;步骤 3: 使用keep-alive组件 &#…

运动耳机什么牌子的好用?最受欢迎的五款运动耳机品牌推荐

城市的喧嚣和繁忙&#xff0c;常常让我们渴望逃离&#xff0c;去寻找一片属于自己的宁静天地。大自然&#xff0c;便是那个能够抚慰我们心灵、让我们重新找回宁静与美好的地方。对于热爱自然、钟情户外的你&#xff0c;一款合适的运动耳机&#xff0c;无疑是探索自然、享受运动…

连连看游戏页面网站源码,直接使用

可以上传自己喜欢的图片 游戏页面 通关页面 源码免费下载地址抄笔记 (chaobiji.cn)

【C语言】每日一题,快速提升(4)!

&#x1f525;博客主页&#x1f525;&#xff1a;【 坊钰_CSDN博客 】 欢迎各位点赞&#x1f44d;评论✍收藏⭐ 题目&#xff1a;实现计算机程序 解答&#xff1a; 该程序运用函数指针数组&#xff0c;具体请看代码 代码&#xff1a; #include <stdio.h> int add(int a…

软考 - 系统架构设计师 - Web 应用真题(2)

问题 1&#xff1a; 淘汰策略&#xff1a;遗留系统技术含量低&#xff0c;业务价值也低&#xff0c;所以需要全面重新开发一个系统来替代遗留系&#xff1b;&#xff08;一般是企业的业务发生了根本变化&#xff0c;遗留系统已经基本不再适应企业运作的需要&#xff1b;或者是遗…

【Android AMS】startActivity流程分析

文章目录 AMSActivityStackstartActivity流程startActivityMayWaitstartActivityUncheckedLocked startActivityLocked(ActivityRecord r, boolean newTask, boolean doResume, boolean keepCurTransition)resumeTopActivityLocked 参考 AMS是个用于管理Activity和其它组件运行…

人类连接的桥梁:探索Facebook如何连接世界

随着技术的发展和全球化的进程&#xff0c;我们的世界正在变得越来越紧密相连。在这个过程中&#xff0c;社交媒体平台扮演了一个至关重要的角色&#xff0c;为人们提供了一个跨越国界、文化和语言的交流平台。其中&#xff0c;Facebook作为全球最大的社交媒体平台&#xff0c;…

Harbor安装手册

安装Docker yum install -y yum-utils device-mapper-persistent-data lvm2 yum-config-manager \ --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo sed -i -e /mirrors.cloud.aliyuncs.com/d -e /mirrors.aliyuncs.com/d \ /etc/yum.repos.d/…

error C2649: “typename”: 不是“class”的解决方法

目录 1.现象 2.解决方法 1.现象 我们定义了一个模版类&#xff0c;代码如下&#xff1a; template<typename X> class CShortWaveLinkProProtocol {friend class X;public:explicit CShortWaveLinkProProtocol() {}virtual ~CShortWaveLinkProProtocol() {}private:vo…

别让商业机密跑了:企业如何锁紧数据大门

Facebook 用户数据泄露&#xff1a;2018年&#xff0c;Cambridge Analytica公司非法获取了8700万Facebook用户的个人数据&#xff0c;并用于政治广告定向&#xff1b;Capital One 金融公司泄密&#xff1a;2019年&#xff0c;美国银行Capital One遭到黑客攻击&#xff0c;导致1…

Bridge 2024---创意无限,数字资产管理新纪元

Bridge 2024是Adobe公司开发的一款强大的视觉管理工具&#xff0c;专为创意工作者和摄影师设计。它提供了一个直观、高效的平台&#xff0c;用于组织、浏览、管理和展示图像、视频和音频文件。Bridge 2024具备全面的资源管理功能&#xff0c;用户可以轻松导入、组织、预览和搜索…

白盒测试之条件组合覆盖

白盒测试之条件组合覆盖&#xff08;蓝桥课学习笔记&#xff09; 实验介绍 使用分支-条件覆盖法设计白盒测试用例时可以使程序中所有判断语句中的条件取值为真、为假的情况和整个判断语句取真分支、假分支的情况都至少被执行过一次&#xff0c;但无法覆盖到所有路径&#xff…

c++-----继承

01&#xff1a;继承是什么 定义 继承 (inheritance) 机制是面向对象程序设计 使代码可以复用 的最重要的手段&#xff0c;它允许程序员在 保 持原有类特性的基础上进行扩展 &#xff0c;增加功能&#xff0c;这样产生新的类&#xff0c;称派生类。继承 呈现了面向对象 程序设计…

Java springboot使用EasyExcel读Excel文件,映射不到属性值,对象属性值都是null

如果你的类上有这个注解&#xff0c;去掉火或注释掉就可以了 Accessors(chain true)解决方法

常用日期组件封装

date.js // 获取近期日期数组 例&#xff1a;["2024-04-04 00:00:00", "2024-04-05 23:59:59"] const getDateRange (num 1) > {const time1 new Date()const diff new Date().getTime() - 86400000 * (num)const time2 new Date(diff)const year…

Canvas使用详细教学:从基础绘图到进阶动画再到实战(海报生成、Flappy Bird 小游戏等),掌握绘图与动画的秘诀

一、Canvas基础 1. Canvas简介 Canvas是HTML5引入的一种基于矢量图形的绘图技术&#xff0c;它是一个嵌入HTML文档中的矩形区域&#xff0c;允许开发者使用JavaScript直接操作其内容进行图形绘制。Canvas元素不包含任何内在的绘图能力&#xff0c;而是提供了一个空白的画布&a…

LLM-01 大模型 本地部署运行 ChatGLM2-6B-INT4(6GB) 简单上手 环境配置 单机单卡多卡 2070Super8GBx2 打怪升级!

写在前面 其他显卡环境也可以&#xff01;但是最少要有8GB的显存&#xff0c;不然很容易爆。 如果有多显卡的话&#xff0c;单机多卡也是很好的方案&#xff01;&#xff01;&#xff01; 背景介绍 目前借到一台算法组的服务器&#xff0c;我们可以查看一下目前显卡的情况 …

一篇出色的答辩状,需要在“答”与“辩”两方面下功夫,你做到了吗?

一篇出色的答辩状&#xff0c;需要在“答”与“辩”两方面下功夫&#xff0c;你做到了吗&#xff1f; 在法律诉讼中&#xff0c;答辩状的重要性不言而喻。它不仅是你回应对方指控的主要手段&#xff0c;也是展示你立场和观点的关键平台。在#李秘书讲写作#看来&#xff0c;一篇…