关于版本迭代后用户停留在之前版本页面,导致某些功能无法使用的解决方案

本文分析了Vue项目中使用懒加载模块在更新版本后出现请求失败的问题,详细介绍了问题的原因在于webpack打包时生成的chunkhash变化导致旧版本的js文件无法加载。文章提供了监听js资源请求错误、判断错误信息、存储并记录相关信息以及防止断网导致的页面刷新问题的解决方案。
1、问题发现

某天发布测试版本后,测试小伙伴,反馈部分按钮点击后没有相关的交互动作,需要刷新后才能正常使用,经常在刚发版本后出现。刚收到问题的时候,第一反应就是缓存问题造成的,那就刷新一下就好了,但经常在发布版本后出现,无论对测试和用户都不能接受该处理方式,所以来研究一下

2、问题分析

项目采用vue(全家桶)+element-ui+webpack+axios搭建,使用vue-router的懒加载,实现按需加载,发版本后无法访问,应该和webpack打包与vue-router懒加载有关。在webpack配置文件webpack.prod.conf.js,查看相关的输出配置

output: {
    path: config.build.assetsRoot,
    filename: utils.assetsPath('js/[name].[hash].js'),
    chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
},

filename是对应于entry里面生成出来的文件名,chunkFilename未被列在entry中,但有些场景需要被打包出来的文件命名配置。比如按需加载(异步)模块的时候,这样的文件是没有被列在entry中的使用CommonJS的方式异步加载模块。

由于项目是异步加载,打包导出问文件也是chunkFilename,从webpack配置文件可以看出,当修改某个文件的时候会修改该chunkhash的值,相关的js修改,用户点击按钮的时候,通过按需加载请求不到上一个版本的js文件,导致页面卡死,无法应答

3、问题解决
1、监听相关js资源请求

使用addEventListener,实现错误监听

    window.addEventListener('error', handleListenerError, true);

* 该监听应放在index.html或项目打包页面的最上面,否则可能无法监听到相关的js请求失败的情况

2、判断相关错误相关信息

1)、判断相关的标签是否是script,eventErr.srcElement.localName == ‘script’

2)、判断是否是自己的按需加载模块的js,eventErr.srcElement.src.indexOf(’/* 域名*/.com/static/js/’);

3)、剔除.js.map的报错,fileName.indexOf(’.js.map’) < 0

3、存储并记录相关信息(防止页面重复刷新)
let reloadObj = {
    hash: hash,
    time: new Date().getTime()
}
let reloadObjlocalStorage = window.localStorage.getItem('reloadObj');
if(reloadObjlocalStorage == null){
    //第一次进来刷新页面
    //存储相关信息
    window.localStorage.setItem('reloadObj',JSON.stringify(reloadObj));
    //刷新界面
    window.location.reload();
}else{
    //第二次进来,判断上一次信息(理论上不应该进来,除非某些特殊情况,例如因某些原因导致部分js文件丢失),防止页面无休止的刷新
    let preReloadObj = JSON.parse(reloadObjlocalStorage);
    let time = new Date().getTime();
    //两次js文件加载报错时间间隔600毫秒才刷新
    if(time > Number(preReloadObj.time) + 600){
        window.localStorage.setItem('reloadObj',JSON.stringify(reloadObj))
        window.location.reload();
    }
}
4、防止中途断网导致页面刷新问题
if(navigator.onLine){ //返回Boolean类型,在线:true,离线:false
    window.addEventListener('error', handleListenerError, true);
}
5、完整代码
if(navigator.onLine){
    window.addEventListener('error', handleListenerError, true);
}
//监听事件
function handleListenerError (eventErr){
    if (eventErr.srcElement.localName == 'script' && 
    eventErr.srcElement.src.indexOf('/*域名*//static/js/')) {
            let arr = eventErr.srcElement.src.split('/static/js/');
            let fileName = arr[1];
            let hash = fileName.split('.')[1]; //获取hash
            if(fileName.indexOf('.js.map')<0){
                let reloadObj = {
                    hash: hash,
                    time: new Date().getTime()
                }
                let reloadObjlocalStorage = window.localStorage.getItem('reloadObj');
                if(reloadObjlocalStorage == null){
                    window.localStorage.setItem('reloadObj',JSON.stringify(reloadObj))
                    //刷新界面,获取新的html文件
                    window.location.reload();
                }else{
                    let preReloadObj = JSON.parse(reloadObjlocalStorage);
                    let time = new Date().getTime();
                    if(time > Number(preReloadObj.time) + 60){
                    window.localStorage.setItem('reloadObj',JSON.stringify(reloadObj))
                    window.location.reload();
                    }
                }
            }
    }
    eventErr.preventDefault()
}
6.刷新页面的作用

html文件中主要有三个js文件:

manifest.[chunkhash].js:在vendor的基础上,再抽取出要经常变动的部分,比如关于异步加载js模块部分的内容。

vendor.[chunkhash].js:通过提取公共模块插件来提取的代码块(webpack本身带的模块化代码部分)

app.[chunkhash].js: 入口js

刷新页面获取新的html,新的html请求上面新的js文件,在新的manifest.[chunkhash].js中包含了最新的异步加载模块的新地址(即js的新路径);

新的html也会包含新的app.[chunkhash].css以便更新新的样式

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值