如何解决微前端中的路由跳转坑
事件背景
商家工作台目前已经使用qiankun 改造成微前端体系,微前端的好处不用我赘述,大家懂的都懂,因此在有品二清项目开发时也以微前端的方式进行接入。在送测过程中,测试同学反馈在点击浏览器回退的时候会页面空白,我一脸蒙圈的试了好几次却没复现,最终在服务端同学跟测试同学的大力配合下,找到了稳定复现的场景。
问题定位
When you have eliminated the impossibles,whatever remains,however improbable,must be the truth. – 福尔摩斯
原因未知,需要继续拆解
以前接入过的子应用有遇到过这种问题呢?就我所知没有
好的,为什么以前的子应用没有遇到过呢?因为以前的子应用跟主应用都是vue2的router
那就是说可能是新旧Router导致的咯?有可能哦~问问其他子应用呢
.....问过了,人家是好的????.....再报再探!
以上是遇到问题时混乱的大脑的疑点闪现过程。从中我们不难找出导致问题的大致范围:主应用的Router版本与子应用的Router版本不一致,当然,中间还存在几个疑点,需要继续拨开迷雾。
- 实现原理有什么差异会导致这个问题。
- 其他
Vue3
项目为啥没遇到这个问题。
带着以上问题,我们开始进入漫长的断点debug 与翻源码过程。
源码分析
真実はいつもひとつ
1. 实现原理的差异
首先,让我们来分析一波新旧版本的 Router
到底更改了什么。
我们在新版本Router
文档中找到这么一段说明。
稍后我们会在源码中找到对应的操作state
的具体位置
而旧版本的Router
使用的pushState
,则只在state
中存储了key这唯一一个属性。(vue-router/src/util/push-state.js
)
history.state
在新旧版本的Router
中的数据结构是不一致的。
我猜这应该是导致改问题的核心因素了。我们接着往下验证
2. undefined 的由来
主应用在点击左侧菜单的时候,会触发
pushState
,从而激活子应用,进入子应用对应的菜单中。子应用在第一次进入的时候,会执行
changeLocation
的replace
操作,此时页面进入子应用内。子应用内部页面跳转时,所有的路由均由子应用
Router
进行接管。此时一切正常。再次点击主应用左侧菜单时,执行以下代码将 history.state 置为空对象。同时,页面跳转到对应路由页面。
history.pushState({}, '', jumpUrl)
继续在子应用内部跳转路由时,如下图所示,当执行到
push(vue-router/history/html5.ts)
的时候,由于此时history.state
已经变成了空对象,所以图中的currentState.current
就变成了undefined
。在265行会先调用一次
changeLocation
用来记录当前路由信息(中间状态)
- 而进入到
changeLocation
方法内部,此时的to
已经变成了undefined
,也因此拼装的url
中会出现undefined
。 - 由于第六步中执行的是中间态的记录当前路由行为,后续还会继续跳转真实的目的地路由,所以中间态的
undefined
被保存在了浏览器的路由栈中。当触发回退的时候,就跳到了url
中带有undefined
resole的空白页面。 - 现在,案情真相大白了。
解决方案
一劳永逸的方案则是:主应用与子应用均使用同一个版本的 VueRouter
,当然,也要从实际出发,综合考虑各项改动的ROI
,从而采用更合理的方案。