一、现象描述
项目线上测试时发现(本地测试未出现该问题):项目更新版本,切换菜单成功后,但是页面还是展示的之前的,且路由未跳转;手动刷新页面后,正常。
控制台异常信息为:
TypeError:failed to fetch dynamically imported module:http://xxxxxxx
Failed to laod module script:Expected a JavaScript module script but the server responeded with a MIME type of "text/html"
二、问题原因
线打包的自动化工具会把上一个版本的资源文件清空,但是vite打包发版后,当前页面缓存的还是发版之前的资源,未主动刷新成新资源,导致跳转页面时在服务器上找不到之前的包,所以出现这种问题。主动刷新后,页面缓存资源更新,跳转正常。
使用vite对项目进行打包,对 js 和 css 文件使用了 chunkhash 进行了文件缓存控制,但是项目的index.html文件在版本频繁迭代更新时,会存在被浏览器缓存的情况。
在发版后,如果用户不强制刷新页面,浏览器会使用旧的index.html文件,在跳转页面时会向服务器端请求了上个版本 chunkhash 的 js 和 css 文件,但此时的文件已经在版本更新时已替换删除了,最终表现为页面卡顿,控制台报错 等。
在 vue-router 里使用了页面模块懒加载,通过 Vite 打包之后,不同于 Webpack ,生成的 dist/assite 文件夹中,会有很多个小的 js 文件,而 Webpack 打包会生成一个大的 app.js 文件。这样的好处是,大大提升了项目首页开屏的速度!
但是缺点上完线之后就暴露出来了,由于上线打包,使用自动化工具,会把之前的项目文件清空,然后把 build 之后的文件移动过来,相当于整个做了一个替换!
所以如果客户端不主动刷新浏览器,用户的本地项目还是上一个版本的,当它需要进行跳转页面或者引入其他的包时,自然在服务器上找不到之前的包了。
三、解决方案
思路:捕捉跳转错误,刷新页面。
使用全局异常处理来监听并捕获错误。在应用的入口文件(通常是 main.js)中添加以下代码:
const app = createApp(App)
//处理问题:线上页面停留一段时间,点击菜单,页面不跳转
window.addEventListener('error', function (event) {
console.log("全局监听异常.addEventListener");
// 判断是否为模块加载异常 Failed to load module script:
console.log("全局监听异常.addEventListener,event==================", event);
if (event.target.tagName == 'LINK') {
console.log("全局监听异常.addEventListener有新版本更新");
window.location.reload()
}
}, true)
app.mount('#app')
网友评论