微前端 qiankun vite vue3

news/2025/3/20 9:56:11/

文章目录

    • 简介
    • 主应用 qiankun-main vue3 vite
    • 子应用 qiankun-app-vue2 webpack5
    • 子应用 qiankun-react webpack5
    • 子应用 quankun-vue3 vite
    • 遇到的问题

在这里插入图片描述

简介

主要介绍以qiankun框架为基础,vite 搭建vue3 项目为主应用,wepack vue2 和 webpack react 搭建的子应用,形成的一个微前端框架。

主应用 qiankun-main vue3 vite

先用vite 创建一个vue3的标准框架 vue-router typescript 这些都可以选上

yarn create vue

主应用还要装上qiankun依赖

yarn add qiankun

创建一个qiankun-config.ts的文件

import { registerMicroApps, start } from 'qiankun'const beforeLoad: (...args: any[]) => any = (app: any) => {console.log('before load', app)
}
const beforeUnmount: (...args: any[]) => any = (app: any) => {console.log('after unmount', app)
}
const beforeMount: (...args: any[]) => any = (app: any) => {console.log('before mount', app)
}
export function registerApps() {try {registerMicroApps([{name: 'app-vue3', // 子应用名称,跟package.json一致entry: '//localhost:7001', // 子应用入口,本地环境下指定端口container: '#sub-container', // 挂载子应用的domactiveRule: '/app/app-vue3', // 路由匹配规则props: {}, // 主应用与子应用通信传值},{name: 'app-react',entry: '//localhost:3000',container: '#sub-container',activeRule: '/app/app-react',props: {},},{name: 'app-vue2',entry: '//localhost:7003',container: '#sub-container',activeRule: '/app/app-vue2',props: {},}],// 生命周期函数 {beforeLoad: [beforeLoad],beforeMount: [beforeMount],afterUnmount: [beforeUnmount],},)start({sandbox: {experimentalStyleIsolation: true, // 沙箱样式隔离},})} catch (err) {console.log(err)}
}

将上面的文件引入main.ts中

import './assets/main.css'
import { registerApps } from './qiankun-config'
import { createApp } from 'vue'
import { createPinia } from 'pinia'import App from './App.vue'
import router from './router'const app = createApp(App)app.use(createPinia())
app.use(router)app.mount('#qiankun') // 记得把html的挂载id dom改一改registerApps()

创建一个专门用来存放子应用的组件 SubContainer.vue

<script setup lang="ts">
</script><template><h1>Container</h1><div id="sub-container"></div>
</template>

改造主应用的路由router/index.ts

import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue'
// import Layout from '../layout/index.vue'
const router = createRouter({history: createWebHistory(import.meta.env.BASE_URL),routes: [{path: '/',name: 'home',component: HomeView,},{// history模式需要通配所有路由,详见vue-router文档path: '/app/app-vue3/:pathMatch(.*)*',name: 'app-vue3',meta: {},component: () => import('@/views/SubContainer.vue'),},{path: '/app/app-react/:pathMatch(.*)*',name: 'app-react',meta: {},component: () => import('@/views/SubContainer.vue'),},{path: '/app/app-vue2/:pathMatch(.*)*',name: 'app-vue2',meta: {},component: () => import('@/views/SubContainer.vue'),},],
})export default router

主应用到这里开发环境基本就改造完成了 yarn dev启动开发环境服务器

子应用 qiankun-app-vue2 webpack5

安装vue2 webpack的项目
全局先安装vue-cli

npm install -g @vue/cli
# OR
yarn global add @vue/cli

配置电脑的环境变量 让vscode能够正确使用vue命令符
https://blog.csdn.net/yi_zongjishi/article/details/124831223
上述引用的文章里说以管理员权限启动vscode来处理vscode不能使用vue 的情况有点问题,实际上是以管理员权限启动powershell来执行那些命令后就可以了。

安装vue2框架

vue create qiankun-vue2

安装vue-router
vue2只能安装vue-router@3

yarn add vue-router@3

改webpack的output配置 和devServer配置
由于vue.confg.js存在,所以改造它就等于改造webpack

// const { defineConfig } = require('@vue/cli-service')
const { name } = require('./package')
module.exports = {devServer: {port: 7003, // 与主应用配置子应用的端口号一致就行headers: {'Access-Control-Allow-Origin': '*', // 处理开发环境因为端口号不同而产生的跨域问题},},configureWebpack: {// output为quankun官方要求的必须的output: {library: `${name}-[name]`,libraryTarget: 'umd', // 把微应用打包成 umd 库格式chunkLoadingGlobal: `webpackJsonp_${name}`,},},transpileDependencies: true,
}

根目录下创建一个名为 public-path.js的文件

// 在window上为qiankun挂载关键参数
if (window.__POWERED_BY_QIANKUN__) {// eslint-disable-next-line no-undef__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__
}

在main.js第一行引入,并对main.js改造

import './public-path'
import Vue from 'vue'
import App from './App.vue'
import router from './router'
// import router from './router'
// import store from './store'Vue.config.productionTip = false // 关闭生产提示let instance = nullfunction render(props = {}) {const { container } = propsinstance = new Vue({router,// store,render: h => h(App)// container 表示 是qiankun主应用访问,限制一下搜索子应用挂载dom的范围,最好能改一下这个id的名称}).$mount(container ? container.querySelector('#vue-app2') : '#vue-app2')
}// 如果不是qiankun主应用下访问,而是子应用独立部署,正常执行render
if (!window.__POWERED_BY_QIANKUN__) {render();
}// 根据qiankun官方要求,子应用需要导出三个生命周期钩子函数bootstrap mount unmount
export async function bootstrap() {console.log('[vue] vue app bootstraped')
}
export async function mount(props) {console.log('[vue] props from main framework', props);render(props)
}
export async function unmount() {
// unmount 的时候摧毁掉整个子应用instance.$destroy()instance.$el.innerHTML = ''instance = null
}

记得改掉html文件挂载dom的id为vue-app2

对router.js进行改造

import VueRouter from "vue-router";
import Vue from "vue";
Vue.use(VueRouter);import Home from "./views/Home.vue";
import About from "./views/About.vue";
const routes = [{path: "/",redirect: "/home",},{path: "/home",component: Home,},{path: "/about",component: About,},
];const router = new VueRouter({mode: "history",base: window.__POWERED_BY_QIANKUN__ ? 'app/app-vue2' : '', // 通过qiankun主应用访问子应用时,base需要设置成为主应用专门挂载子用用所在的路径routes,
});export default router;

webpack 5 下的vue2框架项目在开发环境下的改造就差不多完成了。

子应用 qiankun-react webpack5

先从零安装一个react
https://blog.csdn.net/glorydx/article/details/115104561

安装 react-router-dom
改造App.js

import "./App.css";
import About from "./views/About.tsx";
import Home from "./views/Home.tsx";
import { NavLink, useRoutes,  Outlet} from "react-router-dom";
function App() {const base = window.__POWERED_BY_QIANKUN__ ? "/app/app-react/" : "/";const routes = useRoutes([{ path: base, redirect: base + "home", element: <Home /> },{ path: base + "home", element: <Home /> },{ path: base + "about", element: <About /> },]);return (<div className="app"><h1>React Router Dom</h1><div className="main"><div className="leftToolBar"><NavLink to={base + "home"}>Home</NavLink>{/* 或者如下写法传入标签体 */}<NavLink to={base + "about"}>About</NavLink></div><div className="rightContent">{routes}</div></div><Outlet /></div>);
}export default App;

根目录下的 public-path.js

if (window.__POWERED_BY_QIANKUN__) {// eslint-disable-next-line no-undef__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__
}

改造index.js 最好替换一下挂载的dom id ,同样的需要引入public-path.js

import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import App from "./App";
import reportWebVitals from "./reportWebVitals";
import "./public-path.js";
import { BrowserRouter } from "react-router-dom";
function render(props) {const container = props?.container;const root = ReactDOM.createRoot(container? container.querySelector("#app-react"): document.querySelector("#app-react"));root.render(<BrowserRouter><React.StrictMode><App /></React.StrictMode></BrowserRouter>);
}// 然后加入生命周期即可 同样的三个生命周期导出
export async function bootstrap() {console.log("ReactMicroApp bootstraped");
}/*** 应用每次进入都会调用 mount 方法,通常我们在这里触发应用的渲染方法*/
export async function mount(props) {console.log("ReactMicroApp mount", props);render(props);
}/*** 应用每次 切出/卸载 会调用的方法,通常在这里我们会卸载微应用的应用实例*/
export async function unmount() {console.log("ReactMicroApp unmount");ReactDOM.unmountComponentAtNode(document.getElementById("#app-react"));
}// 如果不是qiankun,正常挂载
if (!window.__POWERED_BY_QIANKUN__) {render();
}
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

改造webpack.config.js 前提是react不会自动暴露这东西,在这之前,你必须执行过 npm run eject 或者yarn eject 去暴露webpack的配置文件

主要是给 output加上qiankun需要的配置

	const packageName = require('../package.json').name;...output: {....library: `${packageName}-[name]`,libraryTarget: 'umd',chunkLoadingGlobal: `webpackJsonp_${packageName}`,},

记得把html挂载的id给换了

<div id="app-react"></div>

如果要引入图片或者其他的什么静态资源
比如react项目本身的logo.svg无法正常显示了
需要在react子项目先把打包方式的hash给干掉
在这里插入图片描述
然后把这个svg不改名的情况下,按照路径给copy到主应用中
在这里插入图片描述
这样qiankun主应用vue3的项目就能正常显示这张图片 如果是其它格式的静态资源也是差不多类似上面的操作

子应用 quankun-vue3 vite

还是同样的方式,先安装一个标准的vite vue3项目 需要有vue-router ts 就行

与webpack 5 的配置方式不同,需要安装依赖 vite-plugin-qiankun
yarn add vite-plugin-qiankun

还是先改造main.ts 记得引入public-path.js 文件内容跟之前一样

import './public-path'
import './assets/main.css'
// alert(1111)
import { createApp } from 'vue'
import { createPinia } from 'pinia'import App from './App.vue'
import router from './router'
import { renderWithQiankun, qiankunWindow } from 'vite-plugin-qiankun/dist/helper'let app: any
function render(props = {}) {// 每一次render都需要创建一个新的app = createApp(App)app.use(createPinia()).use(router)const { container } = props as anyapp.mount(container ? container.querySelector('#app-vue3') : '#app-vue3')
}const bootstrap: (...args: any[]) => any = () => {console.log('vue app bootstraped')
}const mount: (...args: any[]) => any = (props) => {const { container } = propsrender(container)console.log('vue3 app mount')
}const unmount: (...args: any[]) => any = () => {app.unmount()
}const initQianKun = () => {// @ts-ignorerenderWithQiankun({mount,bootstrap,unmount,})// render()
}qiankunWindow.__POWERED_BY_QIANKUN__ ? initQianKun() : render()

改造一下router

import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue'
import { qiankunWindow } from 'vite-plugin-qiankun/dist/helper'
const router = createRouter({history: createWebHistory(qiankunWindow.__POWERED_BY_QIANKUN__ ? '/app/app-vue3/' : '/'),routes: [{path: '/',redirect: '/home',},{path: '/home',name: 'home',component: HomeView,children: [],},{path: '/about',name: 'about',// route level code-splitting// this generates a separate chunk (About.[hash].js) for this route// which is lazy-loaded when the route is visited.component: () => import('../views/AboutView.vue'),},],
})export default router

配置一下vite.config.ts

import { fileURLToPath, URL } from 'node:url'import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// import vueDevTools from 'vite-plugin-vue-devtools'
import qiankun from 'vite-plugin-qiankun'
// https://vite.dev/config/
export default defineConfig({plugins: [vue(),// vueDevTools(),qiankun('app-vue3', {useDevMode: true,}),],resolve: {alias: {'@': fileURLToPath(new URL('./src', import.meta.url)),},},server: {port: 7001,headers: {'Access-Control-Allow-Origin': '*',},},
})

基本上就改造完成了 然后启动就可以正常访问

遇到的问题

当子应用切换路由后,主应用再切换路由,会报错
当路由发生变化时,触发此pushState函数 ,解决qiankun的一个bug
详情查看 https://blog.csdn.net/chaoPerson/article/details/131398285

解决的办法,如链接所示,在主应用加一个router的hook

router.beforeEach((to, from, next) => {// 当路由发生变化时,触发此pushState函数 ,解决qiankun的一个bug// 详情查看 https://blog.csdn.net/chaoPerson/article/details/131398285if (window.history.state === null) {history.replaceState({back: from.path,current: to.path,forward: null,position: NaN,replaced: false,scroll: null}, 'localhost:5173' + to.path);}next();
});

在子应用当路由变化时 执行 window.history.pushState(null, "", "");
比如react

import { useEffect } from "react";
import "./App.css";
import About from "./views/About.tsx";
import Home from "./views/Home.tsx";
import { NavLink, useRoutes } from "react-router-dom";
function App() {const base = window.__POWERED_BY_QIANKUN__ ? "/app/app-react/" : "/";const routes = useRoutes([{ path: base, redirect: base + "home", element: <Home /> },{ path: base + "home", element: <Home /> },{ path: base + "about", element: <About /> },]);// 当路由发生变化时,触发此pushState函数 ,解决qiankun的一个bug// 详情查看 https://blog.csdn.net/chaoPerson/article/details/131398285useEffect(() => {if(window.__POWERED_BY_QIANKUN__) {window.history.pushState(null, "", "");}}, [routes]);return (<div className="app"><h1>React Router Dom</h1><div className="main"><div className="leftToolBar"><NavLink to={base + "home"}>Home</NavLink>{/* 或者如下写法传入标签体 */}<NavLink to={base + "about"}>About</NavLink></div><div className="rightContent">{routes}</div></div></div>);
}export default App;

比如vue2

<template><div id="app"><h1>qiankun vue2</h1><RouterLink to="/home">home</RouterLink><RouterLink to="/about">about</RouterLink><RouterView /></div>
</template><script>
import {RouterView, RouterLink} from 'vue-router'
export default {name: 'App',components: {RouterView,RouterLink},watch : {$route () {// 当路由发生变化时,触发此pushState函数 ,解决qiankun的一个bug// 详情查看 https://blog.csdn.net/chaoPerson/article/details/131398285if(window.__POWERED_BY_QIANKUN__) {window.history.pushState(null,'','')}}}
}
</script><style>
</style>

http://www.ppmy.cn/news/1580568.html

相关文章

Oracle+11g+笔记(11)-数据库的安全管理

Oracle11g笔记(11)-数据库的安全管理 11、数据库的安全管理 11. 1 用户管理 11.1.1 创建用户 创建用户可以采用CREATE USER命令来完成。下面是CREATE USER 命令的语法。 CREATE USER username IDENTIFIED BY password OR IDENTIFIED EXTERNALLY OR IDENTIFIED GLOBALLY AS…

Arduino开发ESP8266环境搭建

一.添加链接 打开Arduino IDE&#xff0c;点击“文件”-“首选项”&#xff0c;并输入网址&#xff1a;“https://arduino.esp8266.com/stable/package_esp8266com_index.json” 点击“确定” 完成设置&#xff0c;进行下一步操作。 二.安装ESP8266 点击 “工具”-“开发板…

Vue 3 中使用 vue - pdf - embed + vue3 - pdfjs 在线预览 PDF

在许多 Web 应用程序中&#xff0c;需要实现 PDF 文件的在线预览功能。Vue 3 作为流行的前端框架&#xff0c;配合 vue - pdf - embed 和 vue3 - pdfjs 库&#xff0c;可以轻松实现这一需求。本文将详细介绍如何在 Vue 3 项目中使用这两个库进行 PDF 在线预览。 完整代码实现及…

npm error gyp info

在使用 npm 安装 Node.js 包时&#xff0c;可能会遇到各种错误&#xff0c;其中 gyp 错误是比较常见的一种。gyp 是 Node.js 的一个工具&#xff0c;用于编译 C 代码。这些错误通常发生在需要编译原生模块的 npm 包时。下面是一些常见的原因和解决方法&#xff1a; 常见原因及…

【免费】怎么将MP4转换为GIF,如何在线实现多媒体文件格式互转

目录 【免费】怎么将MP4转换为GIF&#xff0c;如何在线实现多媒体文件格式互转 小瓜有话说 一、多媒体格式转换在线网站 1、在线网站 2、convertio实践 3、ezgif实践 二、使用桌面软件 1、GIMP&#xff08;免费简单&#xff09; 2、Adobe Photoshop 三、使用命令行工…

算法系列——有监督学习——1.线性回归

一、背景 1. 学习参数&#xff1a; 直线可写为yw0w1*x。这是一次函数&#xff0c;w1是斜率&#xff08;或者叫权重 &#xff09;&#xff0c;w0相当于在y轴上的截距。斜率w1和截距w0是由有监督学习的算法学到的参数&#xff0c;称之为学习参数。在线性回归中&#xff0c;需要…

3.1 在VisionPro脚本中添加CogGraphicLabel

本案例需要实现如下功能&#xff1a; 1.加载toolBlock 2.加载图片&#xff0c; 3.运行Block 4.VisionPro中添加脚本显示数值。 见下图&#xff1a;详细代码&#xff08;C#以及visionPro&#xff09;见下面链接&#xff1a; https://download.csdn.net/download/qq_340474…

OpenManus:无需邀请码的开源版Manus,开启自动化新纪元

对于那些渴望拥有自己的AI助手但苦于无法获取Manus邀请码的用户来说,OpenManus提供了一个绝佳的选择。这款开源项目不仅复刻了Manus的核心功能,还允许用户在自己的电脑上执行包括网页浏览、文件操作和代码编写在内的多种任务。本文将详细介绍OpenManus的功能及其使用方法。 …