前言
当我们重新部署前端项目的时候,如果用户一直停留在页面上并未刷新使用,会存在功能使用差异性的问题,因此,当前端部署项目后,需要提醒用户有去重新加载页面。
技术框架
vue、js、webpack
解决方案
- 编译项目时动态生成一个记录版本号的文件
- 轮询(20s、自己设定时间)这个文件,判断版本号,有新版本则通知用户刷新页面
- 通过监听visibilitychange事件,在页面隐藏时停止轮询,页面显示立马检测一次更新
- 检测到更新后,停止轮询
(感兴趣的可去看方案二:根据打完包之后生成的script src 的hash值去判断
,每次打包都会生成唯一的hash值,只要轮询去判断不一样了,那一定是重新部署了。)
效果
页面右下角提示更新:
代码实现
Step1:在 vue.config.js 实现动态创建版本号文件
if (process.env.VUE_APP_ENV !== "production") {
// 这里我设置的是只在非生产环境自动检测更新(生成version);
// 想要所有环境都自动检测更新,只要写if(process.env.VUE_APP_ENV !== "production")内的内容就好const { writeFile, existsSync } = require('fs')// 动态生成版本号const createVersion = () => {//检测目录是否存在if (existsSync('./public')) {writeFile(`./public/version.json`, `{"version":"${Date.now()}"}`, (err) => {if (err) {console.log('写入version.json失败')console.log(err)} else {console.log('写入version.json成功')}})} else {setTimeout(createVersion, 1000)}}setTimeout(createVersion, 10000)
}
Step2:在src目录下封装 auto-update.js
/** @Description: 自动更新*/let currentVersion // 当前版本
let version // 新版本
// const timeData = 60 * 1000 // 检查间隔时间
const timeData = 20 * 1000 // 检查间隔时间
let hidden = false // 页面是否隐藏
let setTimeoutId
let needTip = true // 默认开启提示// 获取版本号
const getVersion = async () => {return fetch('/version.json?timestep=' + Date.now()).then((res) => res.json())
}// 检查更新
const checkUpdate = async () => {console.log('***************checkUpdate**************')const currentVersion = sessionStorage.getItem("version")version = (await getVersion()).version// 本地没有 version,表示刚进入系统,直接塞值if (!currentVersion) return sessionStorage.setItem("version", version)console.log("🚀 ~ file: auto-update.js:19 ~ version:", version)console.log("🚀 ~ file: auto-update.js:21 ~ currentVersion:", currentVersion)console.log("🚀 ~ file: auto-update.js:23 ~ Number(version) !== Number(currentVersion):", Number(version) !== Number(currentVersion))let needRefresh = falseif (Number(version) !== Number(currentVersion)) {console.log('%c 发现新版本~~~~~~', 'color: red')needRefresh = true}return needRefresh
}// 自动更新
const autoUpdate = async () => {setTimeoutId = setTimeout(async () => {// 页面隐藏了就不检查更新if (!hidden) {const willUpdate = await checkUpdate()console.log("🚀 ~ file: auto-update.js:71 ~ setTimeoutId=setTimeout ~ willUpdate, version:", willUpdate, version)if (willUpdate && needTip) {// 延时更新,防止部署未完成用户就刷新空白setTimeout(()=>{// ----弹框确认---先简单点弹框确认,可以用注释内的,跳过右下角通知的内容(Step3、4)// const result = confirm('发现新版本,点击确定更新')// if (result) {// sessionStorage.setItem('version', version)// location.reload() // 刷新当前页// }// --------------//*****右下角通知提示 */window.dispatchEvent(new CustomEvent("onmessageUpdate", {detail: {msg: "发现系统版本更新,请刷新页面~",version: version},}))//******************* */}, 10000)needTip = false // 关闭更新提示,防止重复提醒}}console.log("🚀 ~ file: auto-update.js:90 ~ autoUpdate ~ needTip: ", needTip)if (needTip) {console.warn('needTip autoUpdate');autoUpdate()}}, timeData)
}// 停止检测更新
const stop = () => {if (setTimeoutId) {clearTimeout(setTimeoutId)setTimeoutId = ''}
}// 开始检查更新
const start = async () => {// currentVersion = (await getVersion()).versionautoUpdate()// 监听页面是否隐藏document.addEventListener('visibilitychange', () => {hidden = document.hiddenconsole.log("🚀 ~ file: auto-update.js:64 ~ document.addEventListener ~ hidden, needTip:", hidden, needTip)// 页面隐藏了就不检查更新。或者已经有一个提示框了,防止重复提示。if (!hidden && needTip) {autoUpdate()} else {stop()}})
}export default { start }
Step3:编写模板 CnNotify.vue 文件
<template><div class="cn_notify"><div class="content"><i class="el-icon-message-solid"></i>{{ msg }}</div><div class="footer"><el-row class="btnBox"><el-button type="primary" @click="onSubmit">确认刷新</el-button><el-button @click="cancle">我知道了</el-button></el-row></div></div>
</template>
<script>
export default {props: {msg: {type: String,default: '',},version: {type: String,default: '',},},data() {return {};},created() {},methods: {// 点击确定更新onSubmit() {sessionStorage.setItem('version', this.version) // 存入版本versionlocation.reload() // 刷新},// 关闭cancle() {this.$parent.close();},},
};
</script>
<style lang='scss' scoped>
.cn_notify {.content {padding: 20px 0;}.footer {display: flex;justify-content: center;}
}
</style>
<style lang='scss'>
.versionNotifyStyle {.el-notification__content {width: 280px !important;}
}
</style>
Step4:app.vue 使用组件CnNotify
<template><div id="app"><router-view /></div>
</template><script>
// 引入CnNotify组件
import CnNotify from "@/components/common/CnNotify/index.vue"
export default {name: 'App',components: {CnNotify, // 注册组件},mounted() {this.watchUpdate()},methods: {watchUpdate() {window.addEventListener("onmessageUpdate", (res) => {console.log("🚀 ~ file: App.vue:20 ~ window.addEventListener ~ res:", res)let msg = res.detail.msg,version = res.detail.versionthis.$notify({title: "版本更新提示",duration: 0,position: "bottom-right",dangerouslyUseHTMLString: true,message: this.$createElement("CnNotify", {// 使用自定义组件ref: "CnNotify",props: {msg: msg,version: version},}),customClass:'versionNotifyStyle', //自定义类名})})},},
}
</script>
Step5:在 main.js 内使用
// 引入自动更新提醒
import autoUpdate from './auto-update'
// 非生产环境使用
process.env.VUE_APP_ENV !== 'production' && autoUpdate.start()