前端重新部署如何通知用户刷新网页?
场景:
有时候上完线,用户还停留在老的页面,用户不知道网页重新部署了,跳转页面的时候有时候js连接hash变了导致报错跳不过去,并且用户体验不到新功能。
设置一个全局路由,在路由跳转的时候获取当前版本号和旧版本号进行对比,如果不一样,就通知客户进行刷新页面
// version.js,与package.json同级 import router from '@/router' import axios from 'axios' // import store from '@/store' router.beforeEach(async (to, from, next) => { console.log('路由跳转') try { // 实时获取的版本号 const realVersion = await getVersion() // version可以存在本地,也可以存在store中 const localVersion = localStorage.getItem('version') || realVersion if (localVersion !== realVersion) { console.log('远端代码有更新', { localVersion, realVersion }) // 通知客户刷新操作 } next() } catch (e) { console.log(e) } }) export const getVersion = () => { return new Promise((resolve, reject) => { axios.get('./package.json', { headers: { 'Cache-Control': 'no-cache' }, baseURL: '' }).then(res => { resolve(res.data.version) }, e => { reject(e) }) }) }
在main中引入version.js
// main ... import { getVersion } from '../plugin/version' // 获取当前版本号 const version = await getVersion() // 存放在本地或者store中 localStorage.setItem('version', version)
新增一个addVersion.js文件,用于每次构建更改版本号,与package.json同级
// 如果是vite打包,需要这两行代码 import { createRequire } from 'module'; const require = createRequire(import.meta.url); //npm run build打包前执行此段代码 let fs = require('fs'); //返回package的json数据 function getPackageJson() { let data = fs.readFileSync('./package.json'); //fs读取文件 return JSON.parse(data); //转换为json对象 } let packageData = getPackageJson(); //获取package的json let arr = packageData.version.split('.'); //切割后的版本号数组 arr[2] = parseInt(arr[2]) + 1; packageData.version = arr.join('.'); //转换为以"."分割的字符串 //用packageData覆盖package.json内容 fs.writeFile( './package.json', JSON.stringify(packageData, null, "\t"), (err) => {} );
执行build命令时增加addVersion文件的执行参数
node ./addVersion.js
tips:另外,如果是vite打包,需要安装vite-plugin-top-level-await依赖
npm install vite-plugin-top-level-await -D
在vite.config.js配置此插件
import topLevelAwait from 'vite-plugin-top-level-await' export default defineConfig({ plugins: [ topLevelAwait({ // The export name of top-level await promise for each chunk module promiseExportName: '__tla', // The function to generate import names of top-level await promise in each chunk module promiseImportName: i => `__tla_${i}` }) ] });
这么做的原因是「ECMAScript」提案 Top-level await 由 Myles Borins 提出,它可以让你在模块的最高层中使用 await 操作符。在这之前,你只能通过在 async 函数或 async generators 中使用 await 操作符。Top-level await 是个新特性,打包不支持此特性
缺点:如果一直不切换路由,将无法及时通知到客户进行页面刷新
另外也有轮询的做法,可以参考:【链接】