首先需要在public目录新建version.json文件(vite打包时会将public文件夹下的内容复制一份到最终生成的dist目录中),再使用axios请求自身服务器(axios.get('/')会被重定向至public文件夹,故此axios.get('/version.json')会请求到public录下的version.json文件)
校验逻辑
import axios from 'axios'; //校验版本号 const vertifyVersion = async () => { //向前端项目请求version.json文件获取版本号 const url = `/version.json?timestamp=${new Date().getTime()}`; const { data: res } = await axios.get(url); const version = localStorage.getItem('RAINBOW_SEA_VERSION'); //如果版本号不存在,向缓存中存入一份 if (!version) return localStorage.setItem('RAINBOW_SEA_VERSION', res.version); //如果版本号存在且与缓存版本号不一致,刷新页面 if (res.version !== version){ location.reload(true); localStorage.setItem('RAINBOW_SEA_VERSION', res.version); }; }; //每五秒调一次校验版本号接口 setInterval(() => { vertifyVersion(); }, 5000);npm run build时自动更新版本号(自写plugin),在vite.config.js中引入并注册使用
import fs from 'node:fs'; /** * 数组内容满十进一 * @param {*} arr * @returns */ const incrementArray = (arr) => { for (let i = arr.length - 1; i >= 0; i--) { if (arr[i] < 9) { arr[i]++; return arr; } else { arr[i] = 0; } } // 所有位都是9,添加新最高位 arr.unshift(1); return arr; }; /**自动更新版本号plugin */ export const versionAutoUpdate = () => { return { name: 'version-auto-update', buildEnd() { // 非正式环境,不执行自动更新版本号操作 if (mode !== "production") return; try { const data = fs.readFileSync('./public/version.json', 'utf8'); const params = JSON.parse(data); const arr = params.version.split('.').map((item) => parseInt(item)); params.version = incrementArray(arr).join('.'); fs.writeFileSync('./public/version.json',JSON.stringify(params)) } catch (error) { console.error(error); } }, }; };配合webworker使用
webworker中(webworker中无法import使用axios,此处用fetch代替,或者你也可以在主线程使用axios发出请求)
//webwork中 //请求版本号 const vertifyVersion = async()=>{ try{ const url = `/version.json?timestamp=${new Date().getTime()}` const res = await fetch(url).then(res=>res.json()) //向主线程发送请求结果 postMessage({ type:'version',message:res }) }catch(err){ console.error(err.msg) } } //定时器轮询 setInterval(()=>{ vertifyVersion() },5000)utils文件中(webworker中无法访问localstorage,故此将这部分逻辑提取到主线程中)
//utils文件夹下 //在vite环境中,worker需要通过此种方式引入文件(在这里导出为后面关闭webworker做准备) let worker ; /**初始化版本校验worker */ export const initVersionWorker = () => { //如果版本不支持直接阻断 if (!window.Worker) return; worker = new Worker(new URL('../workers/version.js', import.meta.url).href) //接收worker信息 worker.onmessage = ({ data }) => { const { type, message } = data; if (type !== 'version') return; //缓存中的版本号 const localVersion = localStorage.getItem('RAINBOW_SEA_VERSION'); //worker请求获取的版本号 const version = message.version; //如果本地版本号不存在,向缓存中存入一份 if (!localVersion) return localStorage.setItem('RAINBOW_SEA_VERSION', version); //如果版本号存在且与缓存版本号不一致,刷新页面 if (localVersion !== version) { localStorage.setItem('RAINBOW_SEA_VERSION', version); window.location.reload(true); } }; }; /**关闭worker*/ export const stopVersionWorker = ()=>{ //如果版本不支持直接阻断 if (!window.Worker) return; //否则关闭worker worker.terminate(); }自写vite插件,打包时自动增加版本号
import fs from 'node:fs'; import path from 'node:path' /** * 数组内容满十进一 * @param {*} arr * @returns */ const incrementArray = (arr) => { for (let i = arr.length - 1; i >= 0; i--) { if (arr[i] < 9) { arr[i]++; return arr; } else { arr[i] = 0; } } // 所有位都是9,添加新最高位 arr.unshift(1); return arr; }; /**自动更新版本号plugin */ export const versionAutoUpdate = () => { return { name: 'version-auto-update', buildEnd() { try { //地址替换成你自己项目的地址 const data = fs.readFileSync(path.join(__dirname,'../../public/version.json'), 'utf8'); const params = JSON.parse(data); const arr = params.version.split('.').map((item) => parseInt(item)); params.version = incrementArray(arr).join('.'); fs.writeFileSync(path.join(__dirname,'../../public/version.json'),JSON.stringify(params)) } catch (error) { throw new Error(error) } }, }; };在vite.config.js中引入自写插件
import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' import AutoImport from 'unplugin-auto-import/vite'; import Components from 'unplugin-vue-components/vite'; import { versionAutoUpdate } from './src/utils/auto-update' // https://vitejs.dev/config/ export default defineConfig({ plugins: [ vue(), AutoImport({ resolvers: [VantResolver()], }), Components({ resolvers: [VantResolver()], }), versionAutoUpdate() ] })推荐在Layout(一般登录过后才会进入Layout)组件的onMounted生命周期使用注册initVersionWorker方法,在onBeforeUnmount生命周期卸载(退出登录前销毁webworker)以确保性能。
<template> <div class="layout"> <router-view /> </div> </template> <script setup> import { onMounted,onBeforeUnmount } from 'vue'; import { initVersionWorker,stopVersionWorker } from '../utils/worker'; onMounted(()=>{ //注册版本校验事件 initVersionWorker() }) //退出登录时关闭webwork停止版本号轮询 onBeforeUnmount(()=>{ stopVersionWorker() }) </script> <style scoped lang="less"></style>