qiankun微前端 主应用vue3+vite、子应用vue3+vite
项目目录结构
主应用
创建主应用:
安装qiankun
配置qiankun
挂载 qiankun
添加子应用展示容器
子应用
创建子应用
安装插件
配置 qiankun
qiankun 官网
项目目录结构
qiankun-base 主应用 vue3 + vite
qiankun-project-1 子应用 vue3 + vite
qiankun-project-2 子应用 vue3 + vite
![图片[1] - qiankun微前端 主应用vue3+vite、子应用vue3+vite - 宋马](https://pic.songma.com/blogimg/20250613/0176efa5789b481389f8fe0e59976ef0.png)
![图片[2] - qiankun微前端 主应用vue3+vite、子应用vue3+vite - 宋马](https://pic.songma.com/blogimg/20250613/18b99a2f5011495eb01d43445021ba96.jpeg)

主应用
创建主应用:
创建vue3 + vite 项目:
npm create vue@latest
安装 Element-Plus 组件库
安装配置方法请看Element-Plus官网:https://cn.element-plus.org/zh-CN/
安装qiankun
npm install qiankun -S
配置qiankun
在 src 目录中创建 qiankun文件夹,并创建index.js 和 config.js文件:
config.js 文件中配置子应用路由,示例代码如下:
export default {
subApps: [
{
name: 'vue1', // 子应用名称,必须跟子应用 package.json 中的 name 一致
entry: 'http://localhost:3001/vue1', // 子应用入口,本地环境下指定端口
container: '#vue1', // 挂载子应用的 DOM
activeRule: '/vue1', // 路由匹配规则
props: {
}, // 主应用与子应用通信传值
},
{
name: 'vue2', // 子应用名称,必须跟子应用 package.json 中的 name 一致
entry: 'http://localhost:3002/vue2', // 子应用入口,本地环境下指定端口
container: '#vue2', // 挂载子应用的 DOM
activeRule: '/vue2', // 路由匹配规则
props: {
}, // 主应用与子应用通信传值
}
]
}
index.js 文件中注册子应用,并启动微服务,示例代码如下:
import {
registerMicroApps, start } from 'qiankun'
import config from './config.js' // 引入的时候必须加 .js 要不然会报错
const {
subApps } = config
// 注册子应用
export function registerApps() {
try {
registerMicroApps(subApps, {
beforeLoad: [
async app => {
// console.log('before load', app)
}
],
beforeMount: [
async app => {
// console.log('before mount', app)
}
],
afterUnmount: [
async app => {
// console.log('before unmount', app)
}
]
})
} catch (err) {
console.warn('qiankun 报错信息', err);
}
}
// 启动
export function qiankunStart() {
registerApps()
// 启动微服务
start({
sandbox: {
experimentalStyleIsolation: true, // 样式隔离
},
})
}
挂载 qiankun
在main.js文件中挂载qiankun,示例代码如下:
// 引入qiankun配置
import {
qiankunStart } from '@/qiankun/index.js'
// 启动qiankun
qiankunStart()

添加子应用展示容器
在App.vue或者别的页面添加子应用展示容器,示例代码如下:
<!-- 菜单-->
<el-menu-item index="/vue1">
<span>项目1</span>
</el-menu-item>
<el-menu-item index="/vue2">
<span>项目2</span>
</el-menu-item>
<!--容器-->
<!-- 子应用容器 -->
<div id="vue1"></div>
<div id="vue2"></div>
App.vue代码如下:
<template>
<div class="common-layout">
<el-container>
<el-aside width="260px">
<div class="logo-container">
<div class="logo">
<span class="logo-icon">Q</span>
<span class="logo-text">Qiankun Admin</span>
</div>
</div>
<el-menu
:router="true"
:default-openeds="['1', '2']"
:unique-opened="true"
background-color="#001529"
text-color="#a6adb4"
active-text-color="#ffffff"
>
<!-- 基座(主应用)中可以放自己的路由 -->
<el-sub-menu index="1">
<template #title>
<span>主应用</span>
</template>
<el-menu-item index="/">
<span>首页</span>
</el-menu-item>
<el-menu-item index="/about">
<span>关于我们</span>
</el-menu-item>
</el-sub-menu>
<!-- 基座中也可以放自己的子应用 -->
<el-sub-menu index="1">
<template #title>
<span>微应用</span>
</template>
<el-menu-item index="/vue1">
<span>项目1</span>
</el-menu-item>
<el-menu-item index="/vue2">
<span>项目2</span>
</el-menu-item>
</el-sub-menu>
</el-menu>
</el-aside>
<el-container>
<el-header>
<h1 class="page-title">
<span class="clip-cuPnlM">qiankun 微前端</span>
</h1>
</el-header>
<el-main>
<!-- 主应用容器 -->
<RouterView />
<!-- 子应用容器 -->
<div id="vue1"></div>
<div id="vue2"></div>
</el-main>
</el-container>
</el-container>
</div>
</template>
<script setup>
import {
RouterLink, RouterView } from "vue-router";
</script>
<style>
html,
body {
margin: 0;
padding: 0;
height: 100%;
overflow: hidden;
}
.common-layout {
height: 100vh;
overflow: hidden;
}
.common-layout .el-container {
height: 100%;
}
.el-container {
display: flex;
flex-direction: row;
}
.el-container > .el-container {
flex-direction: column;
flex: 1;
}
.el-aside {
background-color: #001529;
box-shadow: 2px 0 6px rgba(0, 21, 41, 0.35);
height: 100%;
display: flex;
flex-direction: column;
}
.logo-container {
height: 64px;
padding: 16px;
box-sizing: border-box;
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
flex-shrink: 0;
}
.logo {
display: flex;
align-items: center;
height: 100%;
}
.logo-icon {
width: 32px;
height: 32px;
background: linear-gradient(120deg, #0095ff, #f4f468);
border-radius: 6px;
display: flex;
align-items: center;
justify-content: center;
color: white;
font-size: 20px;
font-weight: bold;
margin-right: 12px;
}
.logo-text {
color: white;
font-size: 18px;
font-weight: 600;
white-space: nowrap;
opacity: 1;
transition: opacity 0.2s;
}
.el-menu {
border-right: none;
background-color: #001529;
flex: 1;
}
.el-menu--popup {
background-color: #001529 !important;
padding: 4px 0 !important;
}
.el-menu--popup .el-menu-item {
color: #a6adb4 !important;
background-color: #001529 !important;
}
.el-menu--popup .el-menu-item:hover,
.el-menu--popup .el-menu-item.is-active {
color: white !important;
background-color: #1890ff !important;
}
.el-sub-menu.is-opened > .el-sub-menu__title {
color: white !important;
}
.el-sub-menu.is-opened > .el-menu--inline {
background-color: #000c17 !important;
}
.el-menu-item {
height: 50px;
line-height: 50px;
font-size: 14px;
padding: 0 20px !important;
margin: 4px 0;
transition: all 0.3s ease;
}
.el-menu-item:hover {
background-color: #1890ff !important;
color: white !important;
}
.el-menu-item.is-active {
background-color: #1890ff !important;
color: white !important;
}
.el-menu-item i,
.el-sub-menu__title i {
transition: color 0.3s ease;
}
.el-sub-menu__title,
.el-menu-item {
position: relative;
overflow: hidden;
}
.el-sub-menu__title::after,
.el-menu-item::after {
content: "";
position: absolute;
left: 0;
right: 0;
bottom: 0;
height: 2px;
background: #1890ff;
transform: scaleX(0);
transition: transform 0.3s ease;
}
.el-menu-item.is-active::after,
.el-sub-menu.is-active > .el-sub-menu__title::after {
transform: scaleX(1);
}
.el-menu--inline {
transition: background-color 0.3s ease;
}
.el-sub-menu.is-opened > .el-sub-menu__title i {
transform: rotate(0);
transition: transform 0.3s ease;
}
.el-menu-item i {
margin-right: 10px;
font-size: 18px;
}
.el-sub-menu {
border-radius: 2px;
}
.el-sub-menu__title {
color: #a6adb4 !important;
height: 50px !important;
line-height: 50px !important;
padding: 0 20px !important;
margin: 4px 0;
}
.el-sub-menu__title:hover {
color: white !important;
background-color: #1890ff !important;
}
.el-sub-menu__title i {
margin-right: 10px;
font-size: 18px;
color: inherit;
}
.el-menu--inline {
background-color: #000c17 !important;
padding: 4px 0;
}
.el-menu--inline .el-menu-item {
height: 40px !important;
line-height: 40px !important;
padding-left: 48px !important;
min-width: auto !important;
}
.el-menu--inline .el-menu-item i {
font-size: 14px;
}
.el-sub-menu.is-active .el-sub-menu__title {
color: white !important;
background-color: #1890ff !important;
}
.el-header {
background-color: #fff;
border-bottom: 1px solid #e6e6e6;
padding: 0 20px;
display: flex;
align-items: center;
height: 60px !important;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
flex-shrink: 0;
}
.page-title {
margin: 0;
}
.page-title > span {
font-size: 32px;
background: -webkit-linear-gradient(120deg, #0095ff 30%, #f4f468);
-webkit-text-fill-color: transparent;
-webkit-background-clip: text;
background-clip: text;
font-weight: 600;
letter-spacing: 0.5px;
}
.el-main {
background-color: #f5f7fa;
padding: 20px;
flex: 1;
overflow-y: auto;
box-sizing: border-box;
height: 0;
}
#vue1,
#vue2 {
background-color: #fff;
border-radius: 8px;
padding: 20px;
margin-bottom: 20px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.05);
}
#vue2 {
margin-bottom: 0;
}
</style>
PS:到这里主应用已经配置完毕
子应用
创建子应用
子应用创建方法跟创建主应用一样。
安装插件
vite-plugin-qiankun:是一个专为 Vite 设计的插件,用于无缝集成 Qiankun 微前端框架,帮助开发者将 Vite 构建的子应用快速接入 Qiankun 主应用。
npm install vite-plugin-qiankun

配置 qiankun
在 vite.config.js 页面中配置如下:
![图片[3] - qiankun微前端 主应用vue3+vite、子应用vue3+vite - 宋马](https://pic.songma.com/blogimg/20250613/02e249fa776f4263a9a1f676be328228.png)
代码如下:
import {
fileURLToPath, URL } from 'node:url'
import {
defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import qiankun from "vite-plugin-qiankun"
// https://vite.dev/config/
export default defineConfig({
base: 'http://localhost:3001',
build: {
target: 'esnext',
minify: 'esbuild',
},
plugins: [
vue(),
qiankun("vue1", {
useDevMode: true,
}),
],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
},
},
server: {
port: 3001,
cors: true,
origin: 'http://localhost:3001',
headers: {
'Access-Control-Allow-Origin': '*'
}
}
})
PS:一定要允许跨域
在 main.js 文件配置如下:
import {
createApp } from 'vue'
import App from './App.vue'
import router from './router/index.js'
import {
renderWithQiankun,
qiankunWindow,
} from "vite-plugin-qiankun/dist/helper";
// const app = createApp(App)
// app.use(router)
// app.mount('#app')
function render(props = {
}) {
const {
container } = props;
const app = createApp(App);
app.use(router);
container
? app.mount(container.querySelector("#app"))
: app.mount("#app");
}
function initApp() {
if (!qiankunWindow.__POWERED_BY_QIANKUN__) {
console.log("%c 独立渲染", "color: #ff0000; font-size: 40px;");
render();
return;
}
renderWithQiankun({
mount(props) {
console.log("%c qiankun 渲染", "color: #ff0000; font-size: 40px;");
render(props);
},
bootstrap() {
},
unmount(props) {
},
update(props) {
},
});
}
initApp();
vite-plugin-vue-devtools 调试工具和 qiankun 不要同时使用,会报奇奇怪怪的错误
PS:这样 qiankun 微前端 vue3 + vite 项目配置完毕,本人测试能正常运行。
项目还未打包上线所以目前还不知道做哪些打包配置,后期持续学习补充笔记。要是有了解的大佬可以留言指点指点,非常感谢。














暂无评论内容