1.问题描述

vue + vite项目:有时跳转页面会卡住,但刷新一下页面又恢复正常,控制台信息如下:

TypeError: Failed to fetch dynamically imported module: xxx

2.信息收集

用户端复现了问题,从现场获取到控制台日志:

vite生产环境报错,TypeError: Failed to fetch dynamically imported module: xxx_主线程

img_16739282021590.png

3.问题分析

从报错来看,动态加载模块失败

单独访问module链接,服务端响应404

查看服务器文件,发现服务端文件,与请求文件的hash不一样, 也就是说服务端文件发生了变更,只有一种情况下,服务端文件会发生变更:有版本发布,并且文件代码有更新,才会导致文件hash值变化。

问题推测:用户在发布版本之前已经打开效能管理平台,在版本发布之后,用户跳转有代码更新的页面便会失败

问题证明:询问用户是在什么时候打开的页面,并通过对比鲸云版本发布时间点,对比结果符合上面的猜想,并通过自定义版本号,在测试环境成功复现问题。

到这里,问题基本确定。

4.问题解决

接下来是如何解决这个问题

问题的本质是:版本发布后,某些资源的链接可能发生变化,如果有用户正打开版本更新前的页面,那么此时跳转页面便有可能失败

问题解决思路:在版本发生变更时,自动重载页面,如此便会获得最新的资源链接

实现思路:

  1. 首先需要标记版本号:版本号已经存在于Jenkinsfile,不过该文件与js文件分离,需要从其中读取出来
  2. 本质上js文件都会下发到客户端,在客户端执行,但浏览器又存在js缓存,因此不能从js变量读取version,读取到的都是发布前的版本号
  3. 可以每次进行代码构建时创建一个version.txt,将版本号写入该文件,并且将该文件在服务端暴露,并服务端设置txt文件不缓存,前端可通过http请求,访问version.txt, 则可读取到最新的版本号
  4. 读取服务端版本号时机选择:有两种方式,一是定时轮询(确定是比较耗费资源),二是用户点击新链接时查询版本号(可在路由守卫中实现,缺点是会影响页面跳转速度)
  5. 由于上面问题是一个较小概率事件,不应该对解决该问题花费过多的代价
    基于方案二,能否在不影响跳转速度的同时,获取最新版本号?可以,也有两种方法:1.使用异步方式获取版本号,2.使用web worker获取版本号
  • 异步方式缺陷:出现异常可能会影响到主线程,异步代码会在同步代码执行完之后进行,版本检测速度会有影响
  • 使用web worker可以解决异步的缺陷,web worker工作在单独的线程,如果worker出现异常不会影响主线程,在多核CPUworker与主线程并行执行,速度会更快,
  • 现代浏览器对web worker的支持也比较不错: