当用户说bug还在是,开发说刷新一下页面

315 阅读1分钟

场景

前端发布了新项目,大家通常的做法就是,运营通知下去,让用户刷新页面,运维这边配置nginx不缓存index.html。一般来说这种处理缓存就够了,但是就是有一些用户,或者运营说,总不能我每次都在群里说记得刷新页面吧,你前端应该主动提醒用户。

思路

每次接口请求前,发送一个接口去判断当前的index.html是否和服务器上的index.html相同,不同就提醒用户刷新页面。至于是每次接口请求还是放在路由钩子上,有待商榷。

实现

vite里面有个钩子transformIndexHtml

image.png 如图所示,那我们就在head里面插入一个meta content就是打包时间,同时生成一个version.json
version.ts 插件:

# version.ts
import { OUTPUT_DIR } from '../../constant';
import { getRootPath } from '../../utils';
import fs, { writeFileSync } from 'fs-extra';
import dayjs from 'dayjs';

function Version() {
  return {
    name: 'version',
    // 转换 index.html 的专用钩子。钩子接收当前的 HTML 字符串和转换上下文
    transformIndexHtml(html) {
      const date = new Date();
      const dateStr = dayjs(date).format('YYYY-MM-DD HH:mm:ss');
      const time = date.getTime();
      const version = `${dateStr}`;
      // 插件version.json
      writeFileSync(
        getRootPath(`${OUTPUT_DIR}/version.json`),
        JSON.stringify({
          version,
        }),
      );
      // 插入meta到head头
      return html.replace(/<\/head>/, `<meta name="version" content="${version}"></head>`);
    },
  };
}

export default Version;

接口请求校验:

import { message } from 'ant-design-vue';
import axios from 'axios';
const env = import.meta.env;
function DiffVersion() {
  if (env.MODE === 'development') {
    return;
  }
  axios
    .request({
      url: '/version.json?t=' + new Date().getTime(),
      method: 'get',
    })
    .then(({ data }) => {
      const { version } = data as any;
      const htmlVersion = (document.querySelector('meta[name=version]') as any)?.content;
      console.log(version, htmlVersion);
      if (version && version != htmlVersion) {
        message.warn('网页已更新,请刷新网页');
      }
    });
}

export default DiffVersion;

另一种

如果不知道不了解vite插件。那也没关系,我们来看,打包后的dist目前。我们通过fs来直接修改文件不一样嘛。

# addVersion.ts
import fs, { writeFileSync, readFileSync } from 'fs-extra';
import path from 'path';

function getRootPath(dir) {
  return path.resolve(process.cwd(), dir);
}

const time = new Date().getTime();
// html 内追加版本号
const htmlPath = getRootPath('dist/index.html');
let htmlStr = readFileSync(htmlPath).toString();

htmlStr = htmlStr.replace(/<\/head>/, `<meta name="version" content="${time}" \/><\/head>`);
writeFileSync(htmlPath, htmlStr);
// public 内追加版本号
const versionJsonPath = getRootPath('dist/version.json');
writeFileSync(
  versionJsonPath,
  JSON.stringify({
    version: time,
  }),
);

然后

#package.json
...
"scripts": 
    "addVersion": "esno  ./build/addVersion.ts",
    "dev": "vite",
    "build": "vite build && npm run addVersion"
    ...
}

解释一下esno 是什么东西。esno 是基于 esbuild 的 TS/ESNext node 运行时