utils/qiankun.js(版本1)
import { addGlobalUncaughtErrorHandler, loadMicroApp } from 'qiankun';
export const micro_conf = [
{
name: 'assistant',
entry: hostMap('http://localhost:7106/assistant/'),
container: '#sub-container1',
activeRule: '/main/assistant',
title: '多方协管'
}
},
{
name: 'safe',
entry: hostMap('http://localhost:7206/safe/'),
container: '#sub-container2',
activeRule: '/main/safe',
config: {
title: '安全监管'
}
}
];
addGlobalUncaughtErrorHandler((event) => {
console.error(event);
const { message: msg } = event;
if (msg && msg.includes('died in status LOADING_SOURCE_CODE')) {
console.error('微应用加载失败,请检查应用是否可运行');
}
});
const lifeCycles = {
beforeLoad: [(app) => console.log('before load', app)],
beforeMount: [(app) => console.log('before mount', app)],
afterUnmount: [(app) => console.log('before unmount', app)]
};
function getProps() {
return {
initialState: {}
};
}
const microList = new Map([]);
let current;
export async function loadMicroAppOnce(to) {
console.log('>>>to', to);
const conf = micro_conf.find(
(item) => ('/main' + to.path).indexOf(item.activeRule) !== -1
);
if (!conf) return;
if (current && current.activeRule === conf.activeRule) {
console.log('>>>未切换应用', current);
return;
}
const cacheMicro = microList.get(conf.activeRule);
if (cacheMicro) {
console.log('>>>已缓存应用', cacheMicro);
return;
}
const micro = loadMicroApp(
{
...conf,
props: getProps(),
lifeCycles
},
{
sandbox: true,
singular: false,
getPublicPath: (entry) => {
console.log('>>>injectPublicPath', entry);
return entry;
}
}
);
await micro.loadPromise;
console.log('>>>加载应用', micro, micro.getStatus());
if (micro.getStatus() === 'BOOTSTRAPPING') {
microList.set(conf.activeRule, micro);
current = conf;
} else {
console.log('>>>加载失败,将卸载应用以待下次重试', micro.getStatus());
current = null;
microList.delete(conf.activeRule);
typeof micro.unmount === 'function' && micro.unmount();
}
}
utils/qiankun.js (版本二:用类重构,支持配置要卸载的应用)
import { addGlobalUncaughtErrorHandler, loadMicroApp } from 'qiankun';
import eventBus from '@/utils/eventBus';
import router from '@/router/index.js';
export const micro_conf = [
{
name: 'assistant',
entry: hostMap('http://localhost:7106/assistant/'),
container: '#sub-container1',
activeRule: '/main/assistant',
title: '多方协管'
}
},
{
name: 'safe',
entry: hostMap('http://localhost:7206/safe/'),
container: '#sub-container2',
activeRule: '/main/safe',
config: {
title: '安全监管'
}
}
];
addGlobalUncaughtErrorHandler((event) => {
console.error(event);
const { message: msg } = event;
if (msg && msg.includes('died in status LOADING_SOURCE_CODE')) {
console.error('微应用加载失败,请检查应用是否可运行');
}
});
const lifeCycles = {
beforeLoad: [(app) => console.log('[LifeCycle] before load', app.name)],
beforeMount: [(app) => console.log('[LifeCycle] before mount', app.name)],
afterMount: [(app) => console.log('[LifeCycle] after mount', app.name)],
beforeUnMount: [(app) => console.log('[LifeCycle] before unmount', app.name)],
afterUnmount: [(app) => console.log('[LifeCycle] after unmount', app.name)]
};
function getProps() {
return {
parentEventBus: eventBus,
parentRouter: router
};
}
class MicroController {
constructor(micro_conf, lifeCycles) {
this.micro_conf = micro_conf;
this.lifeCycles = lifeCycles;
this.microList = new Map();
this.current = null;
}
get currentMicro() {
return this.current && this.microList.get(this.current.activeRule);
}
runLifeCycle(key, app) {
Array.isArray(this.lifeCycles?.[key]) &&
lifeCycles[key].forEach((fn) => fn(app));
}
getConf(path) {
return this.micro_conf.find(
(item) => ('/hg-command' + path).indexOf(item.activeRule) !== -1
);
}
getMicro(path) {
return this.microList.get(path);
}
async load(path) {
const conf = this.getConf(path);
if (!conf) return;
this.runLifeCycle('beforeLoad', conf);
const micro = loadMicroApp(
{
...conf,
props: getProps(),
lifeCycles
},
{
sandbox: true,
singular: false,
getPublicPath: (entry) => {
console.log('>>>injectPublicPath', entry);
return entry;
}
}
);
this.runLifeCycle('beforeMount', conf);
await micro.loadPromise;
if (micro.getStatus() !== 'BOOTSTRAPPING') {
console.log('>>>加载失败,将卸载应用以待下次重试', micro.getStatus());
this.unmount(conf.activeRule);
return;
}
this.runLifeCycle('afterMount', conf);
this.microList.set(conf.activeRule, micro);
this.current = conf;
return micro;
}
unmount(path) {
if (!path) return;
const conf = this.getConf(path);
this.runLifeCycle('beforeUnMount', conf);
const micro = this.getMicro(path);
if (!micro) return;
typeof micro.unmount === 'function' && micro.unmount();
this.microList.delete(path);
if (this.current && path === this.current.activeRule) this.current = null;
this.runLifeCycle('afterUnmount', conf);
}
unmountCurrent() {
this.unmount(this.current.activeRule);
}
}
const microController = new MicroController(micro_conf, lifeCycles);
const willUnmountList = [];
export async function loadMicroAppOnce(to) {
console.log('>>>to', to);
const conf = microController.getConf(to.path);
if (
microController.current &&
microController.current.activeRule === conf.activeRule
) {
return;
}
if (
microController.current &&
willUnmountList.includes(microController.current.name)
) {
microController.unmountCurrent();
}
const cacheMicro = microController.getMicro(conf.activeRule);
if (cacheMicro) {
return;
}
await microController.load(conf.activeRule);
}
subContainer.vue
<template>
<div class="sub-container-wrap">
<div
v-for="micro in micro_conf"
:key="micro.name"
:id="micro.container.replace('#', '')"
v-show="
$route.path &&
('/main' + $route.path).indexOf(micro.activeRule) !== -1
"
class="sub-container-box"
></div>
</div>
</template>
<script setup>
import { loadMicroAppOnce, micro_conf } from '@/utils/qiankun';
const route = useRoute();
watch(
() => route.path,
() => loadMicroAppOnce(route),
{ immediate: true }
);
</script>
<style lang="scss" scope>
.sub-container-wrap {
width: 100%;
height: 100%;
box-sizing: border-box;
display: inline-block;
}
.sub-container-box {
height: 100%;
> div {
height: 100%;
}
}
</style>