micro-app微前端的尝试
背景:项目组需要把crm项目和erp项目,这两个已有的项目集成到一个项目平台上使用。所以使用了micro-app微前端作为基座,crm和erp作为子应用展示。
原理:使用类webcomponent组件把各个子应用集成起来,类似于在基座应用中嵌套iframe页面,使用micro-app暴露出来的方法通讯。可以把不同技术的子应用放到同一个基座中展示。
项目中遇到的问题: 1、子应用、基座和控制台window指向问题。 子应用的上下文和基座的是互相隔离开的,基座和子应用有各自的window挂载不同的数据,控制台中的window是基座的上下文获取的。想要子应用的window只能在代码中log查看
2、子应用中触发路由跳转的实现 一开始用的是``` microApp.router.push
原因:因为从子应用A跳转到子应用b,需要先把子应用a卸载后,挂载子应用B。这个过程是异步的,当执行microApp.router.push跳转是同步的,就会拿不到对应跳转的子应用。
最终实现方法:通过轮询去判断是否已经挂在了目标应用,如果过载了再执行跳转
/**
* 安全的子应用跳转方法
* @description 检查子应用状态后再进行跳转,避免"子应用没有挂载导航失败"的错误
* @param {string} appName - 子应用名称
* @param {string} path - 跳转路径
* @returns {Promise<void>}
*/
async function safeMicroAppNavigation(appName: string, path: string) {
const activeApps = microApp.getActiveApps({
excludeHiddenApp: true,
excludePreRender: true,
});
// 如果子应用已激活且已初始化,直接跳转
if (activeApps?.includes(appName) && isAppInitialized(appName)) {
try {
microApp.router.push({ name: appName, path });
console.log(`✅ 子应用 ${appName} 已激活,直接跳转到 ${path}`);
return;
} catch (error) {
console.error('microApp.router.push 失败,回退到 router.push:', error);
router.push({ path });
return;
}
}
// 子应用未激活,显示加载状态并开始轮询
console.log(`⏳ 子应用 ${appName} 未激活,开始轮询等待...`);
loadingStore.showGlobalLoading('正在跳转页面...');
// 清除之前的定时器
if (microAppActiveCheckTimer !== null) {
window.clearInterval(microAppActiveCheckTimer);
microAppActiveCheckTimer = null;
}
// 开始轮询检查子应用状态
microAppActiveCheckTimer = window.setInterval(() => {
const apps = microApp.getActiveApps({
excludeHiddenApp: true,
excludePreRender: true,
});
console.log(
`🔍 轮询检查: 子应用 ${appName} 是否激活`,
apps?.includes(appName),
);
if (apps?.includes(appName) && isAppInitialized(appName)) {
try {
microApp.router.push({ name: appName, path });
console.log(`✅ 子应用 ${appName} 已激活,跳转到 ${path}`);
// 清除定时器
if (microAppActiveCheckTimer !== null) {
window.clearInterval(microAppActiveCheckTimer);
microAppActiveCheckTimer = null;
}
// 延迟隐藏加载状态,确保子应用路由跳转完成
setTimeout(() => {
loadingStore.forceHideGlobalLoading();
}, 1000);
} catch (error) {
console.error('microApp.router.push 失败,回退到 router.push:', error);
router.push({ path });
loadingStore.forceHideGlobalLoading();
}
}
}, 300);
// 设置超时机制,避免无限轮询
setTimeout(() => {
if (microAppActiveCheckTimer !== null) {
console.warn(`⚠️ 子应用 ${appName} 激活超时,回退到 router.push`);
window.clearInterval(microAppActiveCheckTimer);
microAppActiveCheckTimer = null;
loadingStore.forceHideGlobalLoading();
router.push({ path });
}
}, 10000); // 10秒超时
}
基座还支持向子应用注册路由对象,在子应用中进行跳转。为了以后维护性好一些,还是把所有的跳转放在基座处理(建议)
总结:micro-app可以理解成多项目管理工具,它同样具备属于自己的生命周期、环境变量、和路由管理方式。通过样式隔离和元素隔离加scope区分不同的项目样式,当然这些都是可配置的。还提供了不同应用之间的通讯方式。也可以在基座上层给各个子应用增加插件例如高德地图。当套的子应用不断增加,micro-app加载的速度也会有所变慢,ma提供了预加载方案。