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

在前端开发中,我们通常会使用打包工具(如 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 通知 是顶配方案,适合重型系统。

相关推荐
To_OC8 小时前
别再串行写 await 了,Promise.all 才是并行请求的正确打开方式
前端·javascript·promise
To_OC8 小时前
LC 17 电话号码的字母组合:我的回溯算法,就是从这道题开窍的
javascript·算法·leetcode
vipbic8 小时前
中后台越做越乱后,我用插件化把它救回来了
前端·vue.js
Hyyy8 小时前
Computer Use 适合做什么,不适合做什么——一次真实使用后的思考
前端
小和尚同志8 小时前
前端 AI 单元测试思考与落地
前端·人工智能·aigc
invicinble10 小时前
c端系统,其实更像一个信息展示平台
前端
你怎么知道我是队长10 小时前
JavaScript的变量和数据类型介绍
开发语言·javascript·ecmascript
李姆斯10 小时前
管理是否可以被完全量化
前端·产品经理·团队管理
名字还没想好☜11 小时前
Next.js 中间件实战:鉴权、重定向与 A/B 分流
开发语言·前端·javascript·中间件·react·next.js
广州灵眸科技有限公司11 小时前
瑞芯微RV1126B开发板(EASY-EAI-PI2) INI文件操作
java·前端·javascript·网络·人工智能