前端如何检测新版本,并提示用户去刷新

1,778 阅读1分钟

前端如何检测新版本,并提示用户去刷新

先看效果

在这里插入图片描述

原理

通过轮询index.html文件的内容来计算文件的哈希值前后是否发生了变化

前端工程化的项目中,以Vue为例,webpack或vite打包通常会构建为很多的js、css文件,每次构建都会根据内容生成唯一的哈希值。如下图所示。 在这里插入图片描述

大家可以动手试试,观察一下。

每次构建完index.html中script或link标签引用的地址发生了变化。

代码实现

以Vue+ElementPlus项目为例。在入口文件中引入此文件即可。

// check-version.ts
// 封装了storage,粗暴一点可以用 sessionStorage 代替
import { Storage } from "@/utils/storage";
import { ElLink, ElNotification, ElSpace } from "element-plus";
import { h } from "vue";
import CryptoJS from 'crypto-js';

const storage = new Storage('check-version', sessionStorage);
const APP_VERSION = 'app-version';
let notifyInstance: any;

const generateHash = (text: string): string => CryptoJS.SHA256(text).toString();

const getAppVersionHash = async () => {
  const html = await fetch(`${location.origin}?t=${Date.now()}`).then(res => res.text());
  const newHash = generateHash(html);
  const oldHash = storage.get(APP_VERSION);
  return { newHash, oldHash };
}

const checkVersion = async () => {
  const { newHash, oldHash } = await getAppVersionHash()
  if (oldHash !== newHash) {
    if (notifyInstance) return;
    notifyInstance = ElNotification({
      title: '版本更新',
      message: h(ElSpace, null, () => [
        h('span', '检测到新版本发布!'),
        h(ElLink, { type: 'primary', onClick: () => location.reload() }, () => '立即刷新')
      ]),
      position: 'top-right',
      duration: 0,
      onClose: () => {
        notifyInstance = null
      }
    })
  }
}

const loopCheck = (ms: number) => {
  setTimeout(async () => {
    await checkVersion()
    loopCheck(ms)
  }, ms)
}

document.addEventListener('DOMContentLoaded', async () => {
  console.log("The DOM is fully loaded and parsed.");

  const { newHash } = await getAppVersionHash();
  storage.set(APP_VERSION, newHash, null);

  loopCheck(1000 * 30);
});