1.目标场景
前端打包上线,用户还停留在旧的页面,用户不知道网页重新部署了,发送请求报500或者页面显示不出数据,并且用户体验不到新功能。
2.解决方案(1)
如果后端可以配合话可以用
webSocket
跟后端进行实时通讯,前端部署完之后,后端给个通知,前端检测到Message
进行提示,还可以在优化一下使用EvnentSource
这个跟socket
很像只不过他只能后端往前端推送消息,前端无法给后端发送,我们也不需要给后端发送。
以上方案需要后端配合,奈何后端都很忙,需要纯前端实现。
2.解决方案(2)
根据打完包之后生成的
script src 的hash值去判断
,每次打包都会生成唯一的hash值,只要轮询去判断不一样了,那一定是重新部署了。
3.代码实现
当前使用版本为Vue2.5.2;
需要实现一个简单的发布订阅模式;
在until目录下新建一个AutoUpdate.js文件;
文件路径:src-->until-->AutoUpdate.js
下面是AutoUpdate.js文件
/** * 前端重新部署通知用户刷新网页 */ class Updater { oldScript = []; // 存储第一次值也就是script 的hash 信息 newScript = []; // 获取新的值 也就是新的script 的hash信息 dispatch = {}; // 小型发布订阅通知用户更新了 constructor() { this.oldScript = []; this.newScript = []; this.dispatch = {}; this.init(); // 初始化 this.timing(); } async init() { const html = await this.getHtml(); this.oldScript = this.parserScript(html); }; async getHtml() { const html = await fetch('/').then(res => res.text());//读取index html return html }; parserScript(html) { const reg = new RegExp(/<script(?:\s+[^>]*)?>(.*?)<\/script\s*>/ig) //script正则 return html.match(reg) //匹配script标签 } //发布订阅通知 on(key, fn) { (this.dispatch[key] || (this.dispatch[key] = [])).push(fn) return this; } compare(oldArr, newArr) { const base = oldArr.length; const arr = Array.from(new Set(oldArr.concat(newArr))); //如果新旧length 一样无更新 if (arr.length === base) { // this.dispatch['no-update'].forEach(fn => { // fn(); // }) } else { // 否则通知更新 this.dispatch['update'].forEach(fn => { fn(); }) } }; async timing() { setInterval(async () => { const newHtml = await this.getHtml(); this.newScript = this.parserScript(newHtml); this.compare(this.oldScript, this.newScript) //这边给的是默认值15000,也可以自定义秒数 }, 15000); }; } export default Updater;
然后在main.js文件中引入并使用即可
文件路径:src-->main.js
import Vue from 'vue' import Updater from "./utils/AutoUpdate.js"; //前端重新部署通知用户刷新网页 const AutoUpdate = new Updater() AutoUpdate.on('update',()=>{ setTimeout(async()=>{ const result = confirm('当前网站有更新,请点击确定刷新页面体验'); if(result){ location.reload(); } },500) }) new Vue({ el: '#app', render: h => h(App) });