umijs / qiankun

📦 🚀 Blazing fast, simple and complete solution for micro frontends.
https://qiankun.umijs.org
MIT License
15.83k stars 2.02k forks source link

主应用和子应用都是用Vue3+VueRouter4,点击主应用中菜单进行router.push,对应同一个activeRule的子应用来回切换,会重复创建子应用实例 #1865

Open huangxu510 opened 2 years ago

huangxu510 commented 2 years ago

What happens?

主应用和子应用都是用Vue3+VueRouter4,点击主应用中菜单进行router.push,对应同一个activeRule的子应用来回切换,会重复创建子应用实例 具体表现为

  1. 主应用 Vue2+VueRouter3 子应用Vue2+VueRouter3, 正常
  2. 主应用 Vue2+VueRouter3 子应用Vue3+VueRouter4, 正常
  3. 主应用 Vue3+VueRouter4 子应用Vue2+VueRouter3, 正常
  4. 主应用 Vue3+VueRouter4 子应用Vue3+VueRouter4, 来回切换会重复创建子应用实例

初步感觉是 VueRouter4 和 qiankun 之间的兼容问题,望排查修复

最小可复现仓库

https://github.com/huangxu510/qiankun-test/tree/master

复现步骤,错误日志以及相关配置

1.启动 vue2-base, vue3-base, vue-2-micro-app, vue3-micro-app 2.在vue3-base启动页面中,来回切换 vue3主页和vue3列表 菜单

  1. 可以看到log里面乾坤的生命周期,每次来回切换都会创建子应用实例

image

相关环境信息

huangxu510 commented 2 years ago

有大佬帮忙看看吗

gongshun commented 2 years ago

看了下,VueRouter4的问题,主应用跳转路由时,触发了一个错误的路由,single-spa 监听到了就卸载了子应用。

/vue3 跳转到 /vue3/list 时,中间会跳转到 /list(这一步会触发卸载),然后才跳转到 /vue3/list 。主应用的路由钩子没有监听到这个路由跳转,但是 single-spa 能监听到

huangxu510 commented 2 years ago

看了下,VueRouter4的问题,主应用跳转路由时,触发了一个错误的路由,single-spa 监听到了就卸载了子应用。

/vue3 跳转到 /vue3/list 时,中间会跳转到 /list(这一步会触发卸载),然后才跳转到 /vue3/list 。主应用的路由钩子没有监听到这个路由跳转,但是 single-spa 能监听到

我也看了下,VueRouter4push的时候调用了两个方法 一个replaceState,一个pushState,问题出在replaceState的时候,获取的state.current不对,是因为VueRouter4在histry.state里面有存一些值,然后主应用和子应用的histry.state没有隔离开,导致的这些值串了,获取的state(之前提到的state.current)就不对了

huangxu510 commented 2 years ago

看了下,VueRouter4的问题,主应用跳转路由时,触发了一个错误的路由,single-spa 监听到了就卸载了子应用。

/vue3 跳转到 /vue3/list 时,中间会跳转到 /list(这一步会触发卸载),然后才跳转到 /vue3/list 。主应用的路由钩子没有监听到这个路由跳转,但是 single-spa 能监听到

乾坤官网介绍特性说了 JS 沙箱,确保微应用之间 全局变量/事件 不冲突,现在这个问题的根本原因就是主应用和子应用的vue-router在window.history.state中存的变量相互影响了,那么其实还是乾坤js沙箱的问题吧,希望你们可以深入跟踪一下

huangxu510 commented 2 years ago

有大佬看看这问题吗,着急

YueLiux commented 2 years ago

可以尝试在主应用菜单切换时直接使用 history.pushState();处理,绕过router。

413362848 commented 2 years ago

主应用上跳转用 router.replace 这样的可以防止跳转到空页面 /list 但是会直接跳到vue3这个页面来 算是一个替代的办法

coderja commented 2 years ago

我将pushState替换成replaceState可行

lchxiang commented 1 year ago

可以尝试在主应用菜单切换时直接使用 history.pushState();处理,绕过router。

切换应用的时候会出问题 比如 /app1/sys 切到/app2/sys 使用这个会跳转到 /app1/app2/sys这个地址导致错误

cdxxiaomao commented 1 year ago

我遇到的是,主应用与子应用都用的vueRouter4,发现点击主应用跳转,始终都会unmount然后mount,相当于是多次createApp,我在乾坤unmount的时候,把vue实例都进行了app.unmount(),问题得到了解决。

Ashuangshuang commented 1 year ago

@huangxu510 @gongshun 我现在也遇到了这个问题,主vue2+子vue3,子应用内部切换页面后还会导致返回上级页面路径变为/undefined,请问大佬们,这个问题解决了嘛?

Matsumoto384 commented 1 year ago

可以尝试在主应用菜单切换时直接使用 history.pushState();处理,绕过router。

切换应用的时候会出问题 比如 /app1/sys 切到/app2/sys 使用这个会跳转到 /app1/app2/sys这个地址导致错误

请问有找到解决方法吗,我遇到了同样的问题

hulong-prong commented 1 year ago

解决了吗?我也遇到这个问题了

hulong-prong commented 1 year ago

怎么解决的

cdxxiaomao commented 1 year ago

qiankun 在切换至其他子系统的时候,会调用unmount,这个时候,记得卸载vue。如:

import {createApp} from "vue"

// 创建vue实例
const app = createApp()

// qiankun钩子,在切换子系统的时候qiankun会进行调用,这里记得卸载vue的实例;
export function unmount() {
   app.unmount()
}
hulong-prong commented 1 year ago

qiankun 在切换至其他子系统的时候,会调用unmount,这个时候,记得卸载vue。如:

import {createApp} from "vue"

// 创建vue实例
const app = createApp()

// qiankun钩子,在切换子系统的时候qiankun会进行调用,这里记得卸载vue的实例;
export function unmount() {
   app.unmount()
}

我在qiankun卸载的时候调用了app.unmount()的,问题是同一个activeRule下,不应该出现卸载

hulong-prong commented 1 year ago

有大佬看看这问题吗,着急

请问,你有解决这个问题吗

huangxu510 commented 1 year ago

有大佬看看这问题吗,着急

请问,你有解决这个问题吗

我暂时的解决方法修改了主应用中VueRouter的一段源码,具体是 注释掉 /node_modules/vue-router/dist/vue-router.esm-bundler.js 文件中 changeLocation(currentState.current, currentState, true); 这一行

hulong-prong commented 1 year ago

有大佬看看这问题吗,着急

请问,你有解决这个问题吗

我暂时的解决方法修改了主应用中VueRouter的一段源码,具体是 注释掉 /node_modules/vue-router/dist/vue-router.esm-bundler.js 文件中 changeLocation(currentState.current, currentState, true); 这一行

你的vueRouter 版本是多少

hulong-prong commented 1 year ago

有大佬看看这问题吗,着急

请问,你有解决这个问题吗

我暂时的解决方法修改了主应用中VueRouter的一段源码,具体是 注释掉 /node_modules/vue-router/dist/vue-router.esm-bundler.js 文件中 changeLocation(currentState.current, currentState, true); 这一行

我看了一下,发现是currentState 的地址有问题,因为子应用和主应用共用了history 导致子应用触发后会导致每次触发push 获取currentState 出现问题,然后导致了这个问题,还是隔离不够彻底的问题

hulong-prong commented 1 year ago

有大佬看看这问题吗,着急

请问,你有解决这个问题吗

我暂时的解决方法修改了主应用中VueRouter的一段源码,具体是 注释掉 /node_modules/vue-router/dist/vue-router.esm-bundler.js 文件中 changeLocation(currentState.current, currentState, true); 这一行

我看了一下,发现是currentState 的地址有问题,因为子应用和主应用共用了history 导致子应用触发后会导致每次触发push 获取currentState 出现问题,然后导致了这个问题,还是隔离不够彻底的问题

或者说在子应用触发push的时候改变history.state 的时候加上 base 都能解决

way-Eric commented 1 year ago

有大佬看看这问题吗,着急

请问,你有解决这个问题吗

我暂时的解决方法修改了主应用中VueRouter的一段源码,具体是 注释掉 /node_modules/vue-router/dist/vue-router.esm-bundler.js 文件中 changeLocation(currentState.current, currentState, true); 这一行

我看了一下,发现是currentState 的地址有问题,因为子应用和主应用共用了history 导致子应用触发后会导致每次触发push 获取currentState 出现问题,然后导致了这个问题,还是隔离不够彻底的问题

或者说在子应用触发push的时候改变history.state 的时候加上 base 都能解决 https://www.cnblogs.com/shapeY/p/17356929.html

hulong-prong commented 1 year ago

有大佬看看这问题吗,着急

请问,你有解决这个问题吗

我暂时的解决方法修改了主应用中VueRouter的一段源码,具体是 注释掉 /node_modules/vue-router/dist/vue-router.esm-bundler.js 文件中 changeLocation(currentState.current, currentState, true); 这一行

我看了一下,发现是currentState 的地址有问题,因为子应用和主应用共用了history 导致子应用触发后会导致每次触发push 获取currentState 出现问题,然后导致了这个问题,还是隔离不够彻底的问题

或者说在子应用触发push的时候改变history.state 的时候加上 base 都能解决 https://www.cnblogs.com/shapeY/p/17356929.html

不是同一个问题

huangxu510 commented 1 year ago

有大佬看看这问题吗,着急

请问,你有解决这个问题吗

我暂时的解决方法修改了主应用中VueRouter的一段源码,具体是 注释掉 /node_modules/vue-router/dist/vue-router.esm-bundler.js 文件中 changeLocation(currentState.current, currentState, true); 这一行

你的vueRouter 版本是多少

4.0.15

2317686803 commented 1 year ago

我遇上了类似的问题。 我的主应用和子应用都是vue3+vue-router4+webpack的,然后是主应用将router传入到了子应用(下文称为parentRouter)。 以下是我碰到的一些问题: 1.子应用通过parentRouter.push方法跳回主应用的home页,然后通过浏览器的“回退”按钮不能正确返回到子应用,会丢 失“activeRule”那一部分。 此问题已通过 https://juejin.cn/post/7184334346583539767 解决。

2. 解决完 子应用\父应用之间相互跳转的问题后,又碰上了子应用通过parentRouter.push跳转其他子应用时,会偶然报错 
   http://xxxxxundefined的问题。此问题已通过  [https://www.cnblogs.com/shapeY/p/17356929.html](url) 解决。

3. 补充:在经过上述处理后,我发现主子应用之间、子子应用之间的跳转都没问题了。但是单个子应用之间的跳转,
   会在点击浏览器的“回退”按钮后出现问题,问题表现为:地址栏错误拼接了两层“activeRule” 导致子应用的路由
   不能正常加载。于是我手动进行了去重处理(不知道原因,自己瞎捣鼓做出来的,目前只是能用,期待大佬们的解惑)

以上修改都是在父应用的router前置拦截器中进行处理的,代码如下: image

cjlhll commented 1 year ago

楼主解决了吗?

cjlhll commented 1 year ago

有大佬看看这问题吗,着急

请问,你有解决这个问题吗

我暂时的解决方法修改了主应用中VueRouter的一段源码,具体是 注释掉 /node_modules/vue-router/dist/vue-router.esm-bundler.js 文件中 changeLocation(currentState.current, currentState, true); 这一行

我看了一下,发现是currentState 的地址有问题,因为子应用和主应用共用了history 导致子应用触发后会导致每次触发push 获取currentState 出现问题,然后导致了这个问题,还是隔离不够彻底的问题

或者说在子应用触发push的时候改变history.state 的时候加上 base 都能解决

解决了吗?

2317686803 commented 1 year ago

@cjlhll

router.beforeEach(async (to, from) => { let current = window.location.pathname.split('/') if (current[1] === current[2]) { current = current.slice(2) current = current.join('/') current = current.startsWith('/') ? current : '/' + current history.replaceState({back: from.path, current: window.location.pathname}, to.name, current) } else { history.replaceState({back: from.path, current: window.location.pathname}, to.name, '') } })

image

cjlhll commented 1 year ago

不好使呢,还是会重复卸载子应用。

------------------ 原始邮件 ------------------ 发件人: @.>; 发送时间: 2023年9月1日(星期五) 下午2:25 收件人: @.>; 抄送: @.>; @.>; 主题: Re: [umijs/qiankun] 主应用和子应用都是用Vue3+VueRouter4,点击主应用中菜单进行router.push,对应同一个activeRule的子应用来回切换,会重复创建子应用实例 (Issue #1865)

@cjlhll

router.beforeEach(async (to, from) => { let current = window.location.pathname.split('/') if (current[1] === current[2]) { current = current.slice(2) current = current.join('/') current = current.startsWith('/') ? current : '/' + current history.replaceState({back: from.path, current: window.location.pathname}, to.name, current) } else { history.replaceState({back: from.path, current: window.location.pathname}, to.name, '') } })

— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you were mentioned.Message ID: @.***>

2317686803 commented 1 year ago

@cjlhll 这样嘛,那你再去问问其他大佬,我也是找了很多文章后整理的,我在我项目里是勉强能用

sir-ran commented 1 year ago

遇到同样的问题了,主应用中同一个activeRule切换会卸载子应用重复加载。 vue:3.2.47 vue-router:4.1.6

tianhailiang commented 9 months ago

history.pushState() 官方demo也是用的这个。算是能替代吧

LeonGong commented 8 months ago

个人解决办法:主应用 Vue3+VueRouter4 子应用Vue3+VueRouter4 ,可以解决先卸载后加载问题,以及 子应用内部以及子应用间的路由跳转 activeRule重复问题; //错误路由去重 function checkErrorPath(path) { if (path.lastIndexOf('/app/') != 0) { console.log("ERROR") return path.substring(path.lastIndexOf('/app/'), path.length) } return path } //判断错误路由 function isErrorPath(path) { return path.lastIndexOf('/app/') != 0 } // 基座应用路由守卫 router.beforeEach((to, from, next) => { //历史记录完善 const fullPath = to.fullPath history.replaceState({ back: from.path }, to.name , isErrorPath(fullPath)?checkErrorPath(fullPath):'') if (!window.history.state.current) window.history.state.current = to.fullPath if (!window.history.state.back) window.history.state.back = from.fullPath

if (to.meta.title) { document.title = to.meta.title } next() })

zhangzippo commented 6 months ago

同样的问题

zhangzippo commented 6 months ago

同样的问题

什么时候能解决啊

zhangzippo commented 6 months ago

求官方解决下或者有啥绕开的方案吗

natee commented 3 months ago

切主应用时不使用router,直接用a标签跳转可临时解决