vue3+vite+microapp创建基座应用,umd模式加载多个子应用的菜单,当点击加载某个子应用(使用了pina持久化和sessionStorage缓存)的页面时,点击push到其他页面或其他子应用页面,新路由无法加载变空白了(但是刷新浏览器的话却可以加载内容)?
想请教下这个左侧路由切换子应用,子应用路由容器为空,无法加载渲染是啥原因呢?子应用卸载函数的问题导致的?
下面是此子应用的main.ts代码,
import { createApp } from "vue";
import { createPinia } from "pinia";
import piniaPluginPersistedstate from "pinia-plugin-persistedstate";
import App from "./App.vue";
// import router from './router'
import { createRouter, createWebHashHistory } from "vue-router";
import routes from "./router";
import * as ElementPlusIconsVue from "@element-plus/icons-vue";
import { _sessionStorage } from "./utils/lib/storage";
import { cacheKeyEnum } from "./enums/cacheKeyEnum";
/* ----------------------分割线-umd模式--------------------- */
declare global {
interface Window {
__MICRO_APP_ENVIRONMENT__?: boolean;
__MICRO_APP_BASE_ROUTE__?: string;
__MICRO_APP_NAME__?: string;
microApp?: any;
mount?: () => void; // 添加这一行,声明全局变量
onmount?: () => void; // 添加这一行
unmount?: () => void; // 添加这一行
}
}
let app: any = null;
let router: any = null;
let history: any = null;
// 👇 将渲染操作放入 mount 函数,子应用初始化时会自动执行
window.mount = () => {
console.log("交接班 mount");
history = createWebHashHistory(
window.__MICRO_APP_BASE_ROUTE__
? `/#${window.__MICRO_APP_BASE_ROUTE__}`
: "/"
);
router = createRouter({
history,
routes,
});
//导航守卫
router.beforeEach((to, from, next) => {
if (to.meta.requireAuth) {
const _token = _sessionStorage.get(cacheKeyEnum.TOKEN); //是否有登录后的token缓存
if (_token != null) {
next(); //放行
} else {
//转到登录页
next({ path: "/login" });
}
} else {
next();
}
});
app = createApp(App);
// app.use(createPinia())
const pinia = createPinia();
pinia.use(piniaPluginPersistedstate); //持久化
app.use(pinia);
app.use(router);
//从 @element-plus/icons-vue中导入所有图标并进行全局注册
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
app.component(key, component);
}
app.mount("#app");
//微前端环境
if (window.__MICRO_APP_ENVIRONMENT__) {
// console.log('微应用vite渲染了 -- UMD模式')
// handleMicroData()
}
};
// 👇 将卸载操作放入 unmount 函数,子应用卸载时会自动执行
window.unmount = () => {
console.log("交接班 unmount");
// 安全卸载应用
if (app) {
app.unmount();
history.destroy();
app = null;
router = null;
history = null;
_sessionStorage.clear(); //清空sessionStorage
console.log("交接班 子应用卸载完成");
}
// 清空当前子应用的所有绑定函数(全局数据函数除外)
if (window.__MICRO_APP_ENVIRONMENT__ && window.microApp) {
window.microApp.clearDataListener()
}
};
// 如果不在微前端环境,则直接执行mount渲染
if (!window.__MICRO_APP_ENVIRONMENT__) {
window.mount();
}----20251203补充-----
<router-view :key="route.path"></router-view>
<!-- 添加唯一key,native路由模式切换子应用页面时,促使组件重新渲染 add2025-12-03 -->
<!-- <router-view v-slot="{ Component, route }">
<transition name="fade-transform" mode="out-in">
<keep-alive :include="cachedViews">
<component :is="Component" :key="route.path" />
</keep-alive>
</transition>
</router-view> -->大佬,我今天又试了下,好像不是子应用main.ts卸载的问题,是主应用路由挂载那里,昨天是下面那种写法,当首次加载那个子应用的页面后,后续切换此子应用其他页面或者其他子应用页面都会白屏,但是未进入此子应用,其他子应用切换加载没问题,今天主应用路由挂载那里改成上面那种写法,那个子应用切换加载好像可以啦,这大概是啥原因呢(cachedViews---暂时为空数组)?
从你这个代码看大概率属于以下情况:
你调用的 history.destroy() 很可能没有彻底清掉旧的路由实例,导致旧的 history 残留在内存里。
第一次挂载没问题,但卸载后旧的 vnode / history 仍然存在;第二次挂载时 Vue 再往同一个 DOM 挂载,就会出现空白页或路由不跳。
你使用 _sessionStorage.clear() 清空了整个 sessionStorage,但 Pinia 的持久化插件还会记住旧的 store 状态。
这会导致旧数据(例如 token)仍然被路由守卫读取,从而把用户重定向到错误页面,表现出来就是“路由无效”或白屏。
多个子应用共用 sessionStorage,但你的持久化 key 没做隔离,导致:
卸载后状态残留
下次挂载被旧 store 污染
路由被旧状态拦截
第一次加载:
app → DOM 正常渲染
卸载后:
app 节点销毁了
但 router 的 DOM patch/vnode/history 仍残留
第二次加载:
Vue 尝试再次挂载到同一个节点,但旧 vnode 未清理 → 白屏
router 读取旧 token → 路由跳转失败