采用qiankun架构搭建微前端项目,记录一下
主应用
1.安装qiankun
npm i qiankun
2.src目录新建qiankun.js文件
用于保存主应用配置
- name:唯一项,对应微应用的package.json的name
- entry:访问微应用路径端口
- container:加载微应用容器
- activeRule:匹配微应用base路由(大部分访问不了,就是路由问题)
- props:向微应用初始化时传值,比如传activeRule的值进行统一匹配
javascript
import { registerMicroApps, start } from 'qiankun'
import { qiankunStore } from './store/modules/qiankun';
export function registerQiankunApps() {
registerMicroApps(
[
{
name: 'vue3-micro-app', // 微应用名称
entry: '//192.168.0.61:9301/', // 微应用入口
container: '#micro-app-container', // 容器ID
activeRule: '/vue3-micro-app', // 激活规则
props: {
base:'/vue3-micro-app/',
}
},
{
name: 'vue3-micro-app2', // 微应用名称
entry: '//192.168.0.61:9302/', // 微应用入口
container: '#micro-app-container', // 容器ID
activeRule: '/vue3-micro-app2', // 激活规则
props: {
base:'/vue3-micro-app2/',
}
}
],
{
afterMount: [app => {
console.log('微应用加载完成');
qiankunStore().initState()
}]
}
)
start()
}
3.配置qiankun的初始化数据和监听事件
我是放在store里面了,方便应用间响应监听,也可放到class

typescript
import { defineStore } from 'pinia';
import { ref } from 'vue';
import { initGlobalState } from 'qiankun';
export const qiankunStore = defineStore('qiankun', () => {
const actions = ref<any>(null);
const state= ref({
token: null,
user: null
});
const initState=() => {
setGlobalState(state.value)
}
const initListen = () => {
// 监听状态变化
actions.value.onGlobalStateChange((state:any, prev:any) => {
console.log('主应用观察状态变化:', state, prev);
});
};
const init = () => {
console.log('主应用初始化')
actions.value=initGlobalState(state.value);
initState();
initListen();
};
//用于传值后微应用可以监听
const setGlobalState=(...args:any) => {
return actions.value.setGlobalState(...args);
}
//用于设置传值
const setAppData=(e:any)=>{
state.value.user=e.user;
}
return {
init,
initState,
setGlobalState,
setAppData
};
});
4.配置主应用路由
建立微应用需要在主应用添加路由,可以是布局,或者空页面
javascript
{
path: '/vue3-micro-app/:path(.*)*', // 匹配微应用1
name: 'app1',
component: () => import('../layout/empty.vue'),
},
{
path: '/vue3-micro-app2/:path(.*)*', // 匹配微应用2
name: 'app2',
component: () => import('../layout/empty.vue'),
}
5.组件添加容器
在empty.vue文件中,添加micro-app-container的节点,setAppData方法用于缓存切换路由的传值,在afterMount周期后才开始设值,微应用监听
xml
<template>
<div>
我是外层
<button @click="change">菜单1</button>
<button @click="change2">菜单2</button>
<div id="micro-app-container"></div>
</div>
</template>
<script setup lang="ts">
import {registerQiankunApps} from '../qiankun'
import {type ComponentInternalInstance, getCurrentInstance, onMounted} from "vue";
import { qiankunStore } from '../store/modules/qiankun';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const change=()=>{
proxy.$router.push({
path: '/vue3-micro-app/about',
});
qiankunStore().setAppData({
user:{
name:'第一'
}
})
}
const change2=async ()=>{
await proxy.$router.push({
path: '/vue3-micro-app2/test',
});
qiankunStore().setAppData({
user:{
name:'第二'
}
})
}
onMounted(()=>{
registerQiankunApps();
qiankunStore().init()
})
</script>
微应用
1.安装qiankun
npm i vite-plugin-qiankun
2.修改package.json的name
"name": "vue3-micro-app",
3.修改vite.config.ts文件
与主应用注册的name一致
php
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import qiankun from 'vite-plugin-qiankun'
export default defineConfig({
plugins: [
vue(),
qiankun('vue3-micro-app', { // 与主应用注册的name一致
useDevMode: true
})
],
base: '/',
server: {
host: '0.0.0.0',
port: 9301,
cors: true
}
})
4.修改main.ts文件
- instanceRouter是主应用路由传值的话,需重新生成路由
- 如果不传路由,需在router/index.ts里面配置
history: createWebHistory(qiankunWindow.__POWERED_BY_QIANKUN__ ? '/vue3-micro-app/' : '/')
javascript
import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
// import router from './router';
import store from './store';
import { qiankunStore } from './store/modules/qiankun';
import { constantRoutes } from './router';
import { createWebHistory, createRouter } from 'vue-router';
import {
renderWithQiankun,
qiankunWindow
} from 'vite-plugin-qiankun/dist/helper'
import type { QiankunProps } from "vite-plugin-qiankun/es/helper";
let instance: any = null;
instance = createApp(App)
if (!qiankunWindow.__POWERED_BY_QIANKUN__) {
render({})
}
function render(props: QiankunProps = {}) {
console.log('props', props)
const {container} = props as any;
instance = createApp(App)
//主应用传入的base
const instanceRouter = createRouter({
history: createWebHistory(qiankunWindow.__POWERED_BY_QIANKUN__ ? props.base : '/'),
routes: constantRoutes,
});
instance.use(instanceRouter);
instance.use(store);
instance.mount(
container ? container.querySelector('#app') : document.getElementById('app')
)
qiankunStore().setActions(props)
if (qiankunWindow.__POWERED_BY_QIANKUN__) {
console.log('我正在作为子应用运行')
}
}
// some code
renderWithQiankun({
bootstrap: function (): void | Promise<void> {
// console.log('初始化')
},
mount: function (props: QiankunProps): void | Promise<void> {
render(props)
},
unmount: function (props: QiankunProps): void | Promise<void> {
instance.unmount()
instance._container = null
instance = null;
},
update: function (props: QiankunProps): void {
}
})
5.配置qiankun的监听事件
typescript
import { defineStore } from 'pinia';
import { ref } from 'vue';
function emptyAction() {
}
export const qiankunStore = defineStore('qiankun', () => {
const actions = ref<any>({
onGlobalStateChange: emptyAction,
setGlobalState: emptyAction
});
const initListen = () => {
// 监听状态变化
actions.value.onGlobalStateChange((state:any, prev:any) => {
console.log('1号子应用接收:', state, prev);
});
};
const setActions=(actionsValue:any)=> {
actions.value = actionsValue;
initListen();
}
const setGlobalState=(...args:any) => {
return actions.value.setGlobalState(...args);
}
return {
setActions,
setGlobalState
};
});
6.路由配置
typescript
import { createWebHistory, createRouter } from 'vue-router';
import type { RouteRecordRaw } from 'vue-router';
// 公共路由
export const constantRoutes: RouteRecordRaw[] = [
{
path: '/',
name: 'Home',
redirect: '/about',
},
{
path: '/about',
name: 'About',
component: () => import('../views/index.vue')
},
{
path: '/about2',
name: 'About2',
component: () => import('../views/about2.vue')
}
];
/**
* 创建路由
*/
const router = createRouter({
history: createWebHistory(),
routes: constantRoutes,
});
export default router;