项目场景:
最近在学习qiankun微前端框架,因为公司主要是使用的是vue,并且目标是未来逐步使用vue3,所以决定主应用为vue3+webpack5搭建(之前查资料发现qiankun对于vite的支持还不是非常完善,而且官方的教程也只提供了vue2的,所以选择用webpack),子应用目标要完成vue3和react的项目
问题描述
主应用和Vue3子应用都配置完成并且能够独立运行之后,在主应用中跳转子应用一直会报target container not existed while mounting的错误,如图:
原因分析:
- 子应用和主应用index.html中的根目录id相同
- 子应用在主应用的一个路由页面上
- 官方指南中指出路由过渡动画导致
- 在某个角落写了document.write(全局搜索了,并没有相关代码)
网上能找到的主要报错原因是以上这几个,但很可惜全部都试过了,均不是当前项目的报错原因
- 首先对于3,因为在主应用中直接使用
<router-view/>
,并没有使用transition,所以不存在这个问题 - 针对2,把子应用需要挂载的div直接放在了主应用
App.vue
中,不使用任何其他层嵌套,仍然不能解决报错 - 最后把主应用和子应用的根节点id修改为不同的id,并且在
main.js
挂载时修改对应的id名称,报错依然存在
因为按照官方说法,这个报错是因为在挂载子应用前能找到元素,但在挂载过程中元素消失了,所以又尝试将qiankun的start()
方法从main.js
中移除,放到实际加载子应用的vue中的onMounted()
方法中,并且加了options.prefetch: false
项防止预加载,又加了nextTick
防止页面未完全加载完成。console.log
都能打印到需要挂载的元素,但仍然报错。
onMounted(() => {
console.log('sub vue mounted', document.getElementById('subapp-container'))
nextTick(() => {
console.log('sub vue mounted1', document.getElementById('subapp-container'))
if (!window.qiankunStarted) {
window.qiankunStarted = true;
if (document.getElementById('subapp-container')) {
start({
prefetch: false,
sandbox: {
experimentalStyleIsolation: true,
}
})
}
}
})
实际产生的dom中,结构是这样的:
<div id="main-app">
<div id="sub-app">...</div>
</div>
也就是说子应用其实是加载成功了的,只是没有挂载到应该挂载的节点,整体的document像被重新写了,那么registerMicroApps
和start
方法应该都没有调用错误
这个时候只能怀疑自己是不是项目哪里配置有问题,于是在网上找了其他大佬写的vue3+webpack的demo项目,拉到本地之后运行,还是会报同样的错误(这里需要注意的是,因为package-lock.json内依赖的resolved的registry都是不可访问的源,所以为了能够install成功,我直接删除了lock文件,再进行的install,其实就是这里出的问题)
到这步的时候觉得要不就放弃吧。。。
但是又不死心,于是新建了一个vue2的子应用,配置完成后,竟然可以成功跳转到子应用,那么可以肯定是vue3子应用的原因,而不是主应用的问题。
于是再次回到别人的demo,这次直接对比原始的package-lock.json
文件,发现有些小版本上的差别,比如我在install的时候vue3的最新版本已经到了3.5.21,但demo中实际使用的版本是3.3.4。
解决方案:
最后最快速的解决办法就是固定package.json
中vue的版本号,重新install之后就可以正常运行了。
同时为了确认是否和主应用的版本也有关系,重新install了新旧两个版本的vue,均不受影响,也就是说qiankun子应用如果使用vue3,那么就需要考虑vue3的小版本。
至于vue3从3.3升级到3.5为什么会触发这个报错(或者为什么会overwrite document)就需要后续分析vue的changelog了。