前端重新部署如何通知用户刷新网页?

场景:

有时候上完线,用户还停留在老的页面,用户不知道网页重新部署了,跳转页面的时候有时候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 是个新特性,打包不支持此特性

缺点:如果一直不切换路由,将无法及时通知到客户进行页面刷新

另外也有轮询的做法,可以参考:【链接

 

posted @ 2023-01-31 21:38  JSKevin  阅读(1070)  评论(0编辑  收藏  举报