Appearance
微前端-qiankun
一、解决子应用 vue-router 不一致导致 url 出现 undefined 的问题
js
// 父应用的vue-router配置的beforeEach钩子函数中添加以下代码
if (!history.state.current) {
Object.assign(history.state, { current: from.fullPath });
}二、解决 single spa 超时报错的问题
- 问题:通常发生在打开页面之后没有关闭,很长时间后又点击页面的时候会出现
- 解决:监控错误日志,然后重新加载页面
js
const consoleError = () => {
// 重写console.error,可以捕获更全面的错误信息
const oldError = console.error;
console.error = function (message) {
try {
if (
message &&
message.includes &&
message.includes("single-spa minified message #31")
) {
location.reload();
}
} catch (error) {
console.log(error);
}
};
};
// 全局启用
consoleError();三、子应用 vite 构建的插件兼容
使用 vite-plugin-qiankun 插件
js
// 子应用
// main.ts 入口文件
import { qiankunWindow,renderWithQiankun } from "vite-plugin-qiankun/dist/helper";
const initQiankun = () => {
renderWithQiankun({
bootstrap() {
console.log('子应用初始化')
},
mount(props) {
console.log('子应用挂载', props)
// 部门逻辑或者注册应用。。。
render(props)
}
unmount() {
console.log('子应用卸载')
app.unmount()
}
update(props) {
console.log('子应用更新', props)
}
})
}
if (qiankunWindow.__POWERED_BY_QIANKUN__) {
initQiankun();
} else {
// 单独使用 vue的渲染函数
render();
}
// 路由文件
// 判断是否为子应用,进行构建资源和路由检测
let isMicroSubApp = qiankunWindow.__POWERED_BY_QIANKUN__;
if (!isMicroSubApp && import.meta.env.VITE_ENV === 'production') {
// 生产环境
isMicroSubApp = true
}
// 子路由的应用标识
const workspace = 'micro-admin'
// 路由base
const base = isMicroSubApp ? `/${workspace}/` : '/'应用构建配置
js
// vite.config.ts
import qiankun from "vite-plugin-qiankun";
export default defineConfig({
const name = 'vue-app-admin';
plugins: [
qiankun(name, {
useDevMode: true
})
]
})四、父子应用资源路径冲突问题
父应用构建无需处理
子应用构建配置
所有静态资源加上子应用标识和 __static__
js
// vite.config.ts
import qiankun from "vite-plugin-qiankun";
export default defineConfig((mode) => {
const name = "vue-app-admin";
const workspace = "micro-admin";
const workspaceStatic = `${workspace}/__static__`;
return {
plugins: [
qiankun(name, {
useDevMode: true,
}),
],
build: {
sourcemap: true,
assetsDir: `${workspaceStatic}/`,
rollupOptions: {
output: {
chunkFileNames: `${workspaceStatic}/[name].[hash].js`,
entryFileNames: `${workspaceStatic}/[name].[hash].js`,
assetFileNames: `${workspaceStatic}/[name].[hash].[ext]`,
},
},
},
};
});父应用定义子应用的入口文件和激活标识
js
// childApp.ts
const subApp = [
{
name: "vue-app-admin",
entry: "/micro-admin/__static__/",
activeRule: "/micro-admin",
$meta: {
tile: "微前端-子应用",
},
},
// ......
];网关配置子应用
js
// 定位到各自的子应用机器
"/micro-admin/__static__";五、解决多个子应用共用一个 dom 节点的问题
js
// qiankun.ts
import { registerMicroApps, start } from "qiankun";
import childApps from "./childApps";
import singleSpa from "single-spa";
const genActiveRule = (routePrefix) => {
if (typeof routePrefix === 'string') {
return (location) => location.pathname.startsWith(routePrefix);
}
return (location) => routePrefix.includes(location.pathname);
}
const apps = childApps.map((item) => {
return {
...item,
activeRule: genActiveRule(item.activeRule),
container: '#subapp-viewport',
props: {
routerBase: item.activeRule, // 下发基础路由
getGlobalState: globalState.getGlobalState, // 下发全局状态
}
}
})
registerMicroApps(apps, {
beforeLoad: (app) => {
// 解决切换卡顿问题
singleSpa.setMountMaxTimeout(100000, false, 50000)
console.log('before load-加载前', app.name)
}
beforeMount: (app) => {
console.log('before mount-挂载前', app.name)
}
afterMount: (app) => {
console.log('after mount-挂载后', app.name)
}
beforeUnmount: (app) => {
console.log('before unload-销毁前', app.name)
}
afterUnmount: (app) => {
console.log('after unload-销毁后', app.name)
// 可以处理切换子应用,全局弹出框代码的污染问题
const name = app.name
const names = names.split('-')
if (names.length > 0) {
const childName = names[names.length - 1]
const nodeList = document.querySelectorAll(`.${childName}-message`)
if (nodeList.length > 0) {
nodeList.forEach(node => {
node.remove()
})
}
}
}
})
start({
sandbox: {
}
})六、权限控制
使用全局 window 变量来解决和 sessionStorage 存储来解决
七、样式全局污染问题
使用不同的子应用给不同的 UI 库样式前缀进行解决