【vite + vue3】线上页面停留一段时间,点击菜单,页面不跳转

一、现象描述

项目线上测试时发现(本地测试未出现该问题):长时间停留在某一个页面,切换菜单成功后,但是页面还是展示的之前的,且路由未跳转;手动刷新页面后,正常。

二、报错提示

项目在本地开发没问题,但是打包到测试环境时发现:页面无操作停留一段时间(半小时+)后,页面跳转失效,查看控制台报错


 Failed to load module script: Expected a JavaScript module script but the server responded with a MIME type of "text/html". Strict MIME type checking is enforced for module scripts per HTML spec.

网页中使用了模块脚本(module script),但服务器返回的 MIME 类型是 “text/html”,而不是 JavaScript 类型。根据 HTML 规范,严格的 MIME 类型检查会对模块脚本进行强制执行。 

Uncaught (in promise) TypeError: Failed to fetch dynamically imported module: http://xx.x.x.xx:xxxx/assets/Index-1bd9e109.js

三、问题原因

上线打包的自动化工具会把上一个版本的资源文件清空,但是vite打包发版后当前页面缓存的还是发版之前的资源,未主动刷新成新资源,导致跳转页面时在服务器上找不到之前的包,所以出现这种问题。主动刷新后,页面缓存资源更新,跳转正常。


使用vite对项目进行打包,对 js 和 css 文件使用了 chunkhash 进行了文件缓存控制,但是项目的index.html文件在版本频繁迭代更新时,会存在被浏览器缓存的情况。

在发版后,如果用户不强制刷新页面,浏览器会使用旧的index.html文件,在跳转页面时会向服务器端请求了上个版本 chunkhash 的 js 和 css 文件,但此时的文件已经在版本更新时已替换删除了,最终表现为页面卡顿,控制台报错 等。


在 vue-router 里使用了页面模块懒加载,通过 Vite 打包之后,不同于 Webpack ,生成的 dist/assite 文件夹中,会有很多个小的 js 文件,而 Webpack 打包会生成一个大的 app.js 文件。这样的好处是,大大提升了项目首页开屏的速度!

但是缺点上完线之后就暴露出来了,由于上线打包,使用自动化工具,会把之前的项目文件清空,然后把 build 之后的文件移动过来,相当于整个做了一个替换!

所以如果客户端不主动刷新浏览器,用户的本地项目还是上一个版本的,当它需要进行跳转页面或者引入其他的包时,自然在服务器上找不到之前的包了

四、解决思路

方法一:服务器发版时,上一个版本的asset文件包不删除(不合理)

缺点:

  • 随着频繁发版,服务器端前端项目文件会越来越多,浪费空间;
  • 若旧页面的接口涉及到参数改动等,会引起报错;
  • 流水线使用 docker 打包部署会变得非常麻烦。

方法二:前后端配合,定义一个版本号接口

类似 App 版本更新,每次上线都要定义一个版本号,通过后端接口进行修改和获取版本号,需要前端配合。

缺点:

  • 实现起来相对来说较麻烦;
  • 需要一定时间;

方法三:前端记录比对版本号(方法二简化版)(推荐)

前端打包时,自己生成一个json文件来记录本次打包的版本号,路由跳转的时候,通过请求服务端版本号与本地版本号是否一致,决定是否刷新页面。

ps:

  • 版本号唯一:随机码,uaaId 、随机数、时间戳都可以
     

方法四:记录路由跳转时间,定时刷新

直接通过记录页面跳转的时间,来判断是否刷新,

缺点:

  • 刷新时间可能不够及时,导致发版时间与刷新时间刚好错开;
  • 消耗性能;

方法五:退出登录的时候,刷新页面

方法六:捕捉跳转错误,刷新页面(推荐)

五、解决方法

 方法三具体代码如下

如何解决前端上线之后用户页面不刷新的问题_前端打包hash文件后页面需要刷新问题-CSDN博客文章浏览阅读4.4k次,点赞5次,收藏17次。这种场景就好像是 App 版本更新似的,每次上线都要定义一个版本,这个版本通过后端接口进行修改和获取,但是需要前端和后端一起配合,以及一整套流程控制,数据表维护等。实现起来相对来说较麻烦,需要一定时间。..._前端打包hash文件后页面需要刷新问题https://blog.csdn.net/Kevinblant/article/details/126237531


方法六具体代码如下

import { useRouter } from "vue-router";
const router = useRouter();

// 点击菜单时,捕捉报错,刷新页面
router.onError(error => {
   if (error.message.includes("Failed to fetch dynamically imported module")) {
        // reload():类似于点击浏览器上的刷新页面按钮
        window.location.reload();
   }
 });

参考链接:【已解决】Vite 部署后报错:Failed to fetch dynamically imported module_前端知识库

六、其他

辅助理解链接

1、【该方法没有试过,与上述“五、解决方法”类似】

Vue3+vite前端项目打包升级发版后,不手动刷新,页面跳转文件找不到 - 简书

2、Nginx通过反向代理做负载均衡【该方法没有试过】

vite 打包上线后页面静止一段时间(半小时+)路由跳转无响应_vite 打包上线后页面静止一段时间(半小时+)路由跳转无响应-CSDN博客

3、vue3+vite打包以后,项目切换路由触发(偶发触发)报错【该方法试过,没有生效】

Failed to load module script: The server responded with a non-JavaScript MIME type of “text/html”. - 简书

  • 29
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值