vue3+vite+ts 检测版本更新(实现更新后自动刷新)

1,059 阅读2分钟

由于浏览器默认的缓存策略 导致每次版本更新后 用户如果不进行手动刷新看到的还是旧版本内容 影响用户体验 以下为这两天上网查阅资料后的解决方法 (记录)

思路:在每次打包生产代码时,根据请求服务器端的 version.json 中的版本号和浏览器本地缓存的版本号进行对比来监控版本迭代更新(注意: 要禁止浏览器缓存 index.html 和 version.json!!!)

// 添加 nginx 配置
location ~ .*\.(htm|html|json)?$ {
    expires -1;
}

一、在src目录下的plugins文件夹下创建refreshPlugin.ts文件

import fs from "fs";
import path from "path";
type Version = {
  version: number | string;
};
interface Config {
  publicDir: string;
}

export default ({ version }: Version) => {
  let config: Config = { publicDir: "" };

  return {
    name: "version-plugin", // 必须的,将会在 warning 和 error 中显示
    configResolved(resolvedConfig: Config) {
      // 存储最终解析的配置
      config = resolvedConfig;
    },

    buildStart() {
      // 生成版本信息文件路径
      const file = config.publicDir + path.sep + "version.json";

      // 编译时间作为版本信息
      const content = JSON.stringify({ version });
      writeVersion(file, content);
    },
  };
};

/**
 * 写入文件
 * @param fileName
 * @param version
 */
function writeVersion(
  fileName: string,
  version: string | NodeJS.ArrayBufferView
) {
  fs.writeFile(fileName, version, (err) => {
    if (err) throw err;
  });
}

二、在vite.config.ts中引入插件,并define__APP_VERSION__,这样在打包的时候__APP_VERSION__version.json中的值是保持一致.

import versionPlugin from "./src/plugins/refreshPlugin";
const timeVersion = new Date().getTime();

export default defineConfig(({ mode }: ConfigEnv): UserConfig => {
  return {
    plugins: [
      versionPlugin({
        version: timeVersion,
      }),
    ],
    define: {
      // 定义全局版本信息
      __APP_VERSION__: JSON.stringify(timeVersion),
    },
  };
});

三、在utils文件夹下创建versionCheck.ts文件

import axios from "axios";

export const versionCheck = async () => {
  if (import.meta.env.MODE === "development") return;
  const res = await axios.get("version.json");
  if (__APP_VERSION__ !== res.data.version) {
    // 这里可以根据需求是否弹出询问弹窗还是直接刷新 我这里是直接刷新
    window.location.reload();
  }
};

四、检测版本更新的时机

1.路由切换时检测
router.afterEach(async () => { await versionCheck() })
// 这里借鉴了一位作者的思路:没有在beforEach中判断是避免用户当前在默认页面,点击其他页面时检测到版本变化进行刷新重新回到默认页面,需要再点一次才跳转到想去的页面,这样在交互上不是很好。

2.监听 `visibilitychange` 事件
document.addEventListener("visibilitychange", () => {
  if (document.visibilityState === "visible") versionCheck();
});

3. 资源加载错误时
window.addEventListener('error',(event) =>{ 
// 检测版本更新 
// window.location.reload() 
},true)