面试官最喜欢问的:前端怎么自动检测代码更新?

在前端开发中,我们通常会使用打包工具(如 Vite、Webpack)将 JS/CSS 等资源构建上线,并配合 CDN、浏览器缓存来加速访问。但问题也随之而来:

"我已经发布新版本了,怎么用户还看到旧界面?"

"为啥修复的 bug 还在?"

原因很简单:用户浏览器缓存了旧的静态资源,没有感知新版本的变更。

🎯 目标:前端页面如何自动检测打包更新并提示刷新

关键需求是:

  • 服务器发布了新版本,客户端能"感知"到。
  • 最好不依赖后端数据库或额外接口。
  • 弹窗或强制刷新,提示用户更新。

思考:为啥不直接加 hash?

其实我们打包时已经使用 [hash] 命名资源了,那为啥还要检测更新?

因为:

  • 浏览器对 HTML 本身不会缓存 bust;
  • 页面里写死了旧的 <script src="/main.abcd.js">,不会自动拉新版;
  • 用户长时间不刷新页面就不会拉取新 HTML,自然也没拉到新版 JS。

所以必须在 运行中的前端代码层面 进行更新感知。

方案一:轮询版本文件(最常用)

实现思路:

  1. 打包时生成一个版本文件(如 version.json 或注入 index.html 里的 __BUILD_VERSION__ 字段);
  2. 页面加载后,定时轮询该文件;
  3. 一旦检测到版本变更(比如哈希不同),提示用户刷新。

示例代码:

typescript 复制代码
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 秒轮询一次

或者使用文件指纹思路:

  1. 打包后生成一个 manifest 文件 (比如 asset-manifest.jsonmeta.json),里面记录资源及其 hash;

  2. 页面运行时轮询这个 manifest 文件;

  3. 如果发现文件名或 hash 有变,提示刷新页面。

在 Vite 中添加如下配置:

typescript 复制代码
// vite.config.ts
import { defineConfig } from 'vite'

export default defineConfig({
  build: {
    manifest: true, // 开启 manifest 生成
  }
})

构建后会生成 dist/manifest.json,类似这样:

typescript 复制代码
{
  "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" }
}

前端代码(可封装成检测模块):

typescript 复制代码
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模块):

js 复制代码
// 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 连接,一旦收到推送,就提示刷新页面。

js 复制代码
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 通知 是顶配方案,适合重型系统。

相关推荐
牧天白衣.3 小时前
html中margin的用法
前端·html
NoneCoder3 小时前
HTML与安全性:XSS、防御与最佳实践
前端·html·xss
沃野_juededa3 小时前
关于uniapp 中uview input组件设置为readonly 或者disabled input区域不可点击问题
java·前端·uni-app
哎哟喂_!3 小时前
UniApp 实现分享功能
前端·javascript·vue.js·uni-app
k1955142393 小时前
uniapp常用
前端·javascript·uni-app
wuhen_n5 小时前
CSS元素动画篇:基于页面位置的变换动画
前端·css·html·css3·html5
sql123456789116 小时前
前端——CSS1
前端
Nueuis6 小时前
微信小程序分页和下拉刷新
服务器·前端·微信小程序
小白64026 小时前
前端性能优化(实践篇)
前端·性能优化
白瑕6 小时前
[JavaScript]对象关联风格与行为委托模式
javascript