浏览器延迟
修复bug发布测试环境时,测试同学发出疑问为什么bug没有修改,我们总是说让刷新一下就好了
- 为什么要刷新
因为浏览器不知道代码有更新
- 即使打包加了[contentHash]
- Nginx设置index.html Cache-Control: no-store
总是无法做到浏览器同步更新
解决问题
- 打包注入唯一变量
js
// webpack.config.js
const { DefinePlugin } = require('webpack');
module.exports = {
plugins: [
new DefinePlugin({
__BUILD_VERSION__: JSON.stringify(Date.now()), // 或从 CI/CD 注入
}),
],
};
- 生成version.json加入到build文件中
js
// 保证注入变量及version.json写入值相同
const DEFAULT_BUILD_VERSION = JSON.stringify(Date.now())
module.exports = { plugins:
[ new DefinePlugin({ __BUILD_VERSION__: DEFAULT_BUILD_VERSION, // 或从 CI/CD 注入 }),
{
apply(compiler) {
// 使用 afterEmit 钩子,这个钩子会在资源输出到output目录后触发
compiler.hooks.afterEmit.tap('VersionFilePlugin', () => {
const outputPath = compiler.options.output.path;
// 修复:生成正确的 JSON 格式
const versionData = JSON.stringify({ version: DEFAULT_BUILD_VERSION });
fs.writeFileSync(
path.join(outputPath, 'version.json'),
versionData
);
});
}
}
], };
- 编写检查版本的hooks
js
import { useEffect } from 'react';
import { Modal } from 'antd';
// 加入生产环境才需要,本地开发不需要检查
const isProduction = process.env.NODE_ENV === 'production';
const useCheckVersion = () => {
useEffect(() => {
if (!isProduction) {
return () => {};
}
const checkVersion = async () => {
try {
const res = await fetch(`/version.json?ts=${Date.now()}`, {
cache: 'no-store', // 禁止缓存该请求
});
const { version } = await res.json();
if (!version || !process.env.__BUILD_VERSION__ ||
// 保证判断格式统一
`${version}` !== `${process.env.__BUILD_VERSION__}`)
{
Modal.info({
title: '发现新版本',
content: '请刷新页面以获取最新版本',
onOk: () => {
window.location.reload();
},
okText: '刷新',
});
}
} catch (error) {
// 添加更详细的错误信息
if (error instanceof Error) {
// eslint-disable-next-line no-console
console.error('Error details:', {
message: error.message,
stack: error.stack,
});
}
}
};
// 场景1:页面首次加载时检查(即使index.html被缓存也可以解决)
checkVersion();
// 场景2:页面从后台切回时检查
const handleVisibilityChange = () => {
if (document.visibilityState === 'visible') {
checkVersion();
}
};
document.addEventListener('visibilitychange', handleVisibilityChange);
// 场景3(可选):定时轮询(每小时一次)
const interval = setInterval(checkVersion, 3600000);
return () => {
document.removeEventListener('visibilitychange', handleVisibilityChange);
clearInterval(interval);
};
}, []);
};
export default useCheckVersion;
这样在我们发布新版本时就可以解决大部分缓存问题,但是还是做不到实时更新,除非后端介入