记录---前端怎么自动检测代码更新?
🧑💻 写在开头
点赞 + 收藏 === 学会🤣🤣🤣
在前端开发中,我们通常会使用打包工具(如 Vite、Webpack)将 JS/CSS 等资源构建上线,并配合 CDN、浏览器缓存来加速访问。但问题也随之而来:
“我已经发布新版本了,怎么用户还看到旧界面?”
“为啥修复的 bug 还在?”
原因很简单:用户浏览器缓存了旧的静态资源,没有感知新版本的变更。
🎯 目标:前端页面如何自动检测打包更新并提示刷新
关键需求是:
- 服务器发布了新版本,客户端能“感知”到。
- 最好不依赖后端数据库或额外接口。
- 弹窗或强制刷新,提示用户更新。
思考:为啥不直接加 hash?
其实我们打包时已经使用 [hash]
命名资源了,那为啥还要检测更新?
因为:
- 浏览器对 HTML 本身不会缓存 bust;
- 页面里写死了旧的
<script src="/main.abcd.js">
,不会自动拉新版; - 用户长时间不刷新页面就不会拉取新 HTML,自然也没拉到新版 JS。
所以必须在 运行中的前端代码层面 进行更新感知。
方案一:轮询版本文件(最常用)
实现思路:
- 打包时生成一个版本文件(如
version.json
或注入index.html
里的__BUILD_VERSION__
字段); - 页面加载后,定时轮询该文件;
- 一旦检测到版本变更(比如哈希不同),提示用户刷新。
示例代码:
const CURRENT_VERSION = __BUILD_VERSION__; // 构建时注入变量 setInterval(() => { fetch('/version.json?t=' + Date.now()) .then(res => res.json()) .then(({ version }) => { if (version !== CURRENT_VERSION) { alert('检测到新版本,点击确定刷新页面'); window.location.reload(true); } }); }, 10000); // 每 10 秒轮询一次
或者使用文件指纹思路:
-
打包后生成一个 manifest 文件(比如
asset-manifest.json
或meta.json
),里面记录资源及其 hash; -
页面运行时轮询这个 manifest 文件;
-
如果发现文件名或 hash 有变,提示刷新页面。
在 Vite 中添加如下配置:
// vite.config.ts import { defineConfig } from 'vite' export default defineConfig({ build: { manifest: true, // 开启 manifest 生成 } })
构建后会生成
dist/manifest.json
,类似这样:{ "index.html": { "file": "index.html", "isEntry": true }, "src/main.ts": { "file": "assets/main.abc123.js", "isEntry": true }, "src/style.css": { "file": "assets/style.def456.css" } }
前端代码(可封装成检测模块):
let currentVersionHash = '' function getHashFromManifest(manifest: any): string { // 自定义 hash 生成方式:可拼接所有文件路径,也可只取主入口 return Object.values(manifest) .map((entry: any) => entry.file) .join('|') } async function checkForUpdate() { try { const res = await fetch(`/manifest.json?_t=${Date.now()}`) const manifest = await res.json() const newHash = getHashFromManifest(manifest) if (!currentVersionHash) { currentVersionHash = newHash } else if (currentVersionHash !== newHash) { console.log('🚨 发现新版本,准备刷新页面') alert('检测到新版本,点击确认刷新页面') window.location.reload(true) } } catch (err) { console.error('版本检查失败', err) } } setInterval(checkForUpdate, 10000) // 每 5 秒检查一次
💡
manifest.json
中的文件路径含 hash,只要内容变,hash 就会变,就能准确识别版本是否更新。
优点:
- 实现简单,支持所有现代浏览器;
- 可手动控制提示逻辑,提升用户体验;
- 和打包工具(Vite/Webpack)配合紧密。
缺点:
- 本质上还是轮询,数据拉取有频率;
- 如果用户挂着页面一整天,刷新前所有交互还是旧代码。
方案二:WebSocket(配合 CI/CD 或打包系统)
✅ 前提:
- 服务端拥有 WebSocket 服务能力(如 Node.js +
ws
模块); - 每次前端构建部署完成后,触发一次“更新通知”。
服务端(nodejs+ws模块):
// ws-server.js const WebSocket = require('ws'); const wss = new WebSocket.Server({ port: 8080 }); const clients = new Set(); wss.on('connection', (ws) => { console.log('🚀 New client connected'); clients.add(ws); ws.on('close', () => { clients.delete(ws); }); }); // 通知所有客户端刷新页面 function notifyClients() { for (let client of clients) { if (client.readyState === WebSocket.OPEN) { client.send(JSON.stringify({ type: 'update', message: 'new-version' })); } } } // 模拟触发更新(实际应在构建完成后调用) setTimeout(() => { console.log('🎉 New version released, notifying clients...'); notifyClients(); }, 10000); // 10 秒后触发
如果你有配套的部署平台或打包平台(如 Jenkins、Vercel、Netlify),可以在部署成功后广播一条“版本已更新”的消息。
客户端建立 WebSocket 连接,一旦收到推送,就提示刷新页面。
if ('WebSocket' in window) { const ws = new WebSocket('ws://localhost:8080'); ws.onopen = () => { console.log('[WS] Connected to update server'); }; ws.onmessage = (event) => { const data = JSON.parse(event.data); if (data.type === 'update') { console.log('[WS] New version detected'); // 这里可以是弹窗提醒,或者直接刷新 if (confirm('检测到新版本,是否立即刷新页面?')) { window.location.reload(); } } }; ws.onclose = () => { console.log('[WS] Connection closed'); }; ws.onerror = (err) => { console.error('[WS] Error:', err); }; }
可封装为插件或独立模块进行复用,比如 Vue 插件、React Hook、Vite 插件等。
优点:
- 实时;
- 可以配合更多更新逻辑(如强制下线);
缺点:
- 成本高,依赖后端支持,对于检测更新的需求一般无需这么实时;
- 不适合资源有限的小项目;
总结
前端页面检测更新并不是“有没有后端通知”,而是我们主动地检测自己的版本是否已经被 CDN 或打包平台更新。 轮询 version.json
是最稳定、兼容性最强的方案; WebSocket 通知 是顶配方案,适合重型系统。