前端检测新版本,通知用户更新

11,118 阅读3分钟

项目技术栈:vue3 + ant design vue + ts + vite

版本号如何加?我的做法是在打包的时候,用当前打包时间作为版本的唯一标识。

  • 首先封装一个vite的plugin,功能是在打包/构建时动态写入版本号。在根目录新建myPlugins/buildLifeHooks。内容如下:
import fs from 'fs';
import path from 'path';

// 在Vite配置中添加一个插件,监听build事件
export function buildLifeHook() {
  return {
    name: 'build-life-hook',
    buildStart(){
      let now = new Date().toLocaleString().replace(/\//g,'-')
      let version = {
        version:now,
      }
      let versionPath = path.join(__dirname,'../public/version/versionData.json');
      fs.writeFile(versionPath,JSON.stringify(version),'utf8',(err)=>{
        if(err){
          console.log('写入文件失败');
        }else{
          console.log('写入文件成功');
        }
      })
      console.log('构建开始!' + now);
    },
    buildEnd() {
      let now = new Date().toLocaleString().replace(/\//g,'-')
      console.log('构建完成!' + now);
    },
  };
}

vite.config.ts中导入:

import { buildLifeHook } from './myPlugins/buildLifeHook';
...
defineConfig({
...
plugins:[buildLifeHook()],
})

此时版本号文件就生成了,并且每次打包后这个文件的内容都不一样。


下一步就是监听新版本发布。

  • 我的思路是通过轮询获取线上json,之后与本地的版本记录相比,如果相同则什么也不做,如果不同,则弹窗通知用户更新版本,确认更新后,刷新页面即可获取新版本。
  • 当然用户如果正在操作系统,不方便更新,也可以选择暂时忽略更新,此时清除轮询,等待用户后续手动刷新页面即可。
  • 接下来是代码实现:在utils文件夹下新建checkVersions.ts文件。内容如下:
import { Modal } from 'ant-design-vue'
/**
 * @description 检测版本更新
 * @param allowIgnore 是否允许忽略
 * @param timer 传入定时器
 * @returns 
 */
export async function checkUpdate(allowIgnore:boolean, timer?:any) {
  //动态获取线上的资源地址,其实就是vite.config.ts的base的值
  let basePath = import.meta.env.VITE_PUBLIC_PATH
  try {
    // 检测前端资源是否有更新
    let response = await fetch(`${basePath}/version/versionData.json`,{
      headers: {
        'Cache-Control': 'no-cache'
      }
    }).then(res => res.json())
    if(!localStorage.getItem('v3_version')){
      localStorage.setItem('v3_version',response.version)
    }else{
      if(localStorage.getItem('v3_version')!==response.version){
        Modal.destroyAll()
        Modal.confirm({
          title: '检测到新版本',
          content: '是否立即更新?',
          okText: '更新',
          cancelText: '忽略',
          cancelButtonProps:{
            // 是否禁用
            disabled:!allowIgnore
          },
          onOk: () => {
            localStorage.setItem('v3_version',response.version)
            window.location.reload()
          },
          onCancel: () => {
            if(timer!=null && timer!==undefined){
              clearInterval(timer)
            }
          }
        })
      }
    }
  } catch (e) {
    return Promise.reject(e)
  }
}
/**
 * @description 初始化版本检测器
 */
export function initVersionCheck(){
  // checkUpdate(false)
  let timer = setInterval(()=>{
    checkUpdate(true,timer)
  },60000)
}

轮询间隔我设置的1分钟。读者可以按照实际情况调整。

APP.vue中引入该文件:

import {  initVersionCheck } from '@/utils/checkVersion'
import { computed, onMounted, ref } from 'vue';

...
onMounted(() => {
  initVersionCheck()
})

之后就可以正常检测版本更新啦。

image.png

这只是一种简单的版本更新检测方法,一定还有很多其他的实现方式,后续有时间我会再更新,也欢迎读者一起探讨。

2024-06-02更新。

  1. fetch请求的时候,添加如下配置:已在上文中加上,目的是解决浏览器缓存机制可能的导致问题。
headers: {
        'Cache-Control': 'no-cache'
      }
  1. 关于请求时机的说明:轮询或者放在路由守卫中都是可以的,因为加版本号、检查更新的checkUpdate函数,初始化更新检查的initVersionCheck,这三个方法的逻辑是分开写的,所以读者可以灵活运用,按照自己需要调整即可。