前端项目发版后用户需要手动刷新页面获取的解决方案
背景我们的项目是后台管理系统,框架是Vue,构建工具是Webpack。问题每一次修改代码后打包发布到生产环境后,用户需要手动刷新才能获取到最新的代码。原因Webpack打包之后会根据文件内容生成一个hash值,然后再按照[name].[hash].js的格式生成文件名;然后再根据文件的路由对应关系生成一个runtime.[hash].js的文件,这个文件会监控浏览器的路由变化去服务器加...
背景
我们的项目是后台管理系统,框架是Vue
,构建工具是Webpack
。
问题
每一次修改代码后打包发布到生产环境后,用户需要手动刷新才能获取到最新的代码。
原因
Webpack
打包之后会根据文件内容生成一个hash
值,然后再按照[name].[hash].js
的格式生成文件名;
然后再根据文件的路由对应关系生成一个runtime.[hash].js
的文件,这个文件会监控浏览器的路由变化去服务器加载对应的js
文件。
而runtime.[hash].js
文件是放在index.html
中,在开始进入系统时已经加载。
所以当服务器重新发版之后,生成的文件会出现hash
值改变,这时候当用户跳转路由时,请求加载的文件名在服务器上已经找不到了,就会报错:Loading chunk [name].[hash].js failed
方案
思路:既然能监控到加载js
的错误信息,那么就可以在处理错误信息的代码中加入刷新页面的功能,让页面自动去刷新页面,然后再获取最新的runtime.[hash].js
文件,用户再次点击时就可以正常访问了。
按照思路,分为以下2步:
-
找到处理错误信息的代码,加入刷新页面逻辑
经过几番查找,处理错误信息的代码在
runtime.[hash].js
中,如下:var u = new Error; d = function(a) { o.onerror = o.onload = null, clearTimeout(b); var c = r[e]; if (0 !== c) { if (c) { var t = a && ("load" === a.type ? "missing" : a.type), f = a && a.target && a.target.src; u.message = "Loading chunk " + e + " failed.\n(" + t + ": " + f + ")", u.type = t, u.request = f, c[1](u) } r[e] = void 0 } }
难点在于,
runtime.[hash].js
是由webpack
单独生成的,我们不能通过项目中的代码来修改,而且暂时没有找到通过配置的方式来修改。目前的临时解决方案:
通过
Loading chunk
关键字在webpack
模块中找到了对应的文件,文件地址:webpack/lib/web/JsonpMainTemplatePlugin.js
,找到处理错误代码,并添加刷新页面代码:Template.indent([ "if(chunk) {", Template.indent([ "var errorType = event && (event.type === 'load' ? 'missing' : event.type);", "var realSrc = event && event.target && event.target.src;", "error.message = 'Loading chunk ' + chunkId + ' failed.\\n(' + errorType + ': ' + realSrc + ')';", "error.type = errorType;", "error.request = realSrc;", "chunk[1](error);" ]), "}", "location.reload(ture)", // 在此处添加刷新页面代码 "installedChunks[chunkId] = undefined;" ]),
重新执行
npm run build
命令就可以了问题的来了,自动布署时会重新拉取
webpack
包,还是不能生效。解决方案就是自己
Fork webpack
项目,修改以上代码后,再自己发布一个npm
包,然后将项目中的
webpack
引用名改成自己的npm
包名,这样就可以了,缺点就是后续的升级比较麻烦。 -
刷新页面时,取消缓存,获取最新的文件
自动刷新解决了,发现浏览器并没从服务器上拉取文件,原因就是浏览器缓存了。
解决方案:在文件请求路径添加参数,参数值设置为
hash
值,比如:<script src="/static/js/runtime.68e22691.js?t=68e22691"> <link href="/static/css/vendors.bbf38da36d1cd1d96a5e.css?t=cd1d96a5e" rel="stylesheet">
怎么配置呢?
找到
webpack
的output
,设置成如下:output: { path: OUTPUT_PATH, publicPath: '/', filename: 'static/js/[name].[chunkhash:8].js?t=[chunkhash:8]', chunkFilename: 'static/js/[name].[chunkhash:8].js?t=[chunkhash:8]' }
优化
按照目前的解决方案,确实可以实现不再需要手动刷新获取最新的资源,但是有个问题就是刷新之后并不会跳转到用户点击的页面,还是停留在当前页面,需要再点击一次才到跳转。
所以我们可以在刷新之前,弹出一个确认框,告知用户服务器发版或升级了,需要刷新页面才能获取最新的资源。用户点击确认之后再进行刷新操作。
更多推荐
所有评论(0)