场景
前端发布了新项目,大家通常的做法就是,运营通知下去,让用户刷新页面,运维这边配置nginx不缓存index.html。一般来说这种处理缓存就够了,但是就是有一些用户,或者运营说,总不能我每次都在群里说记得刷新页面吧,你前端应该主动提醒用户。
思路
每次接口请求前,发送一个接口去判断当前的index.html是否和服务器上的index.html相同,不同就提醒用户刷新页面。至于是每次接口请求还是放在路由钩子上,有待商榷。
实现
vite里面有个钩子transformIndexHtml。
如图所示,那我们就在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 运行时