解决方案
在项目打包时,将index.html文件中加入打包时的时间戳,当用户第一次进入页面时,获取index.html中的时间戳并保存。然后通过轮询的方式,每隔一段时间请求一下index.html资源,并且根据请求到的内容,来获取对应的时间戳,当保存的时间戳和最新获取的时间戳相同,则表示没有更新,如果不同则表示有新代码发布,提示用户刷新页面。
一、打包时增加打包时间,在index.html中使用
// vue.config.js
module.exports = {
chainWebpack: (config) => {
config.plugin("html").tap(([options]) => {
const saveTemplateParameters = options.templateParameters;
options.templateParameters = (...args) => ({
...saveTemplateParameters.apply(options, args),
BUILD_TIME: new Date().getTime(), // 增加BUILD_TIME字段
});
return [options];
});
},
};
二、index.html文件中使用BUILD_TIME字段
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title><%= htmlWebpackPlugin.options.title %></title>
<!-- 方案一:项目中需要引入配置文件,在引入地址后面加上打包时间 -->
<script src="<%= BASE_URL %>config.js?<%= BUILD_TIME %>"></script>
<script>
</head>
<body>
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
<!-- 方案二:没有配置文件,可以将BUILD_TIME放到dom中,只要能获取到该值就行 -->
<div id="build-time" style="display: none;"><%= BUILD_TIME %></div>
</body>
</html>
三、轮询获取index.html文件,并校验时间戳是否变更
// app.vue 中,或者 main.js 中
<script>
import axios from "axios";
export default {
name: "App",
data() {
return {
buildTime: null,
timeId: null,
};
},
mounted() {
if (process.env.NODE_ENV === "production") {
this.openCheckUpdate();
}
},
methods: {
// 开启更新检测
openCheckUpdate() {
const outerHTML = document.documentElement.outerHTML;
this.buildTime = this.getBuildTime(outerHTML);
this.pollingGetNewHtml();
},
// 轮询获取html
pollingGetNewHtml() {
this.timeId = setInterval(async () => {
const { data } = await axios.get("/index.html");
const nowBuildTime = this.getBuildTime(data);
if (this.buildTime !== nowBuildTime) {
this.closeCheckUpdate();
this.notifyUpdate();
}
}, 2000);
},
// 关闭更新检测
closeCheckUpdate() {
if (this.timeId) {
clearInterval(this.timeId);
this.timeId = null;
}
},
// 通知用户
notifyUpdate() {
console.log('请刷新页面同步最新代码'); // eslint-disable-line
// TODO:可以弹出提示框或者直接让页面刷新等等
},
// 通过正则获取buildTime
getBuildTime(outerHTML) {
const [, buildTime] = /config\.js\?(\d+)/g.exec(outerHTML) || [];
return buildTime;
},
},
beforeDestroy() {
this.closeCheckUpdate();
},
};
</script>
如果是将buildTime放入dom中,只有获取buildTime方式不同
getBuildTimeOfDom(outerHTML) {
const execArr = /<div id="build-time" style="display: none;">\d+<\/div>/g.exec(outerHTML) || [];
return execArr[0].replace(/<[^>]+>/g,'');
},