解决Vue项目每次更新浏览器缓存问题

问题:用户死活看不到新版本

SPA 项目部署完,产品经理说他改不出新的功能。F12 一看,加载的还是上次发布的 app.123abc.js,新 commit 完全没生效。让他强刷一下 (Ctrl+F5) 立刻就好,但你没法要求所有用户都来这一下。

本质是浏览器缓存没失效。Vue / Webpack 默认 hash 文件名(app.[hash].js)按理说能自动 cache-bust,但很多项目里:

  • 构建 hash 策略没开,文件名一直是 app.js(覆盖式发布)
  • 有,但 index.html 自身被 CDN / 浏览器缓存了,里头引用的还是老 hash
  • Service Worker 或 PWA 缓存层把旧文件锁住

解决Vue项目每次更新浏览器缓存问题

方案一:文件名加时间戳查询串

最简单粗暴的方案 —— 每次构建给静态文件加 ?v=时间戳 查询串。哪怕文件名不变,query 变了浏览器就当成新资源重新拉:

// vue.config.js (Vue CLI / webpack 项目)
const path = require('path')
const timeStamp = new Date().getTime()

function resolve(dir) {
    return path.join(__dirname, dir)
}

module.exports = {
    configureWebpack: {
        name: 'XiaoDong',
        resolve: {
            alias: {
                '@': resolve('src')
            }
        },
        output: {
            filename: `js/[name].js?v=${timeStamp}`,
            chunkFilename: `js/chunk.[id].js?v=${timeStamp}`
        }
    },
    css: {
        extract: {
            filename: `css/[name].css?v=${timeStamp}`,
            chunkFilename: `css/chunk.[id].css?v=${timeStamp}`
        }
    }
}

构建后 index.html 里引用变成:

<script src="js/app.js?v=1700000000000"></script>
<link rel="stylesheet" href="css/app.css?v=1700000000000">

每次构建 timeStamp 变,等于每次发布都换 URL。

原理:为什么 query 变就重拉

浏览器决定"用不用缓存"的核心 key 是 URL(包括 query)。app.js?v=1app.js?v=2 在浏览器看来是两个不同的资源,即使服务器返回的内容一样,浏览器也会重新发请求。

CDN 也一样,URL 不同就当作不同资源,缓存独立。

方案二:Vite 项目里的做法

Vite 默认就有 hash,但同样可以加 timestamp:

// vite.config.ts
import { defineConfig } from 'vite'

const timestamp = Date.now()

export default defineConfig({
    build: {
        rollupOptions: {
            output: {
                entryFileNames: `js/[name]-${timestamp}.js`,
                chunkFileNames: `js/[name]-${timestamp}.js`,
                assetFileNames: `assets/[name]-${timestamp}.[ext]`
            }
        }
    }
})

这种把 timestamp 嵌进文件名(不是 query),效果一样,部分 CDN 对 query 的处理不一致,文件名更稳。

方案三:开 hash 但配置 index.html 不缓存

更标准的方案,既保留 hash 又防 index.html 缓存:

Vue / Webpack hash 配置(默认就开了,确认下):

// vue.config.js
module.exports = {
    filenameHashing: true,  // 默认 true,JS/CSS/字体都加 contenthash
    productionSourceMap: false
}

Nginx 给 index.html 设置 no-cache:

server {
    listen 80;
    root /var/www/dist;

    # 带 hash 的静态文件,强缓存 1 年
    location ~* .(js|css|woff2?|png|jpe?g|gif|svg|ico)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
    }

    # index.html 永不缓存
    location = /index.html {
        add_header Cache-Control "no-cache, no-store, must-revalidate";
        add_header Pragma "no-cache";
        add_header Expires "0";
    }

    # SPA fallback
    location / {
        try_files $uri $uri/ /index.html;
    }
}

这套是最佳实践:

  • JS / CSS 带 hash,内容变 hash 变,filename 变就重拉,内容不变就走强缓存(1 年)
  • index.html 不缓存,每次访问都拉新的,新 hash 立即生效

方案四:Service Worker / PWA 场景

如果项目接了 PWA / Service Worker,情况复杂一点。Service Worker 会主动缓存所有资源,普通的 hash 也救不了 —— 它直接拦截请求返回缓存内容。

解决:Service Worker 注册时加版本检测,新版本到达就清旧 cache:

// public/sw.js
const VERSION = 'v-' + new Date().toISOString()  // 构建时替换

self.addEventListener('install', (e) => {
    self.skipWaiting()  // 新版立刻接管
})

self.addEventListener('activate', (e) => {
    e.waitUntil(
        caches.keys().then(keys =>
            Promise.all(
                keys.filter(k => k !== VERSION).map(k => caches.delete(k))
            )
        )
    )
    self.clients.claim()
})

更省心的方案是用 Workbox(vite-plugin-pwa / workbox-webpack-plugin),它自动处理版本控制和清理。

哪种方案选哪个

方案 优势 劣势
时间戳 query 配置最简,一行加完 没变的文件也重拉,浪费带宽
hash + index.html no-cache 只重拉变了的文件,最优 要改 Nginx,稍麻烦
Service Worker 版本控制 PWA 场景必备 复杂,debug 难

验证缓存策略生效

F12 打开 Network,刷新页面,看每个资源的"Status"和"Size"列:

  • 200 + 实际 size → 真实下载
  • 200 (from disk cache) → 浏览器走强缓存,没发请求
  • 304 Not Modified → 发了请求,服务器告诉浏览器内容没变

理想状态:第一次访问全 200 真实下载,刷新后所有带 hash 的资源是 disk cache,index.html 是 200 或 304。

一句话总结

能 hash + nginx 配置就走最佳实践,赶时间或者控制不了服务器配置时,时间戳 query 一行救命。两个本质都是"让浏览器认为这是个新资源",方法不同效果一样。

—— 别看了 · 2026
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理 邮箱1846861578@qq.com。
技术教程

前端项目使用await-to-js异步代码优化利器

2023-9-26 16:04:00

技术教程

Vue移动端适配vw和 postcss-px-to-viewport使用

2023-10-13 17:00:52

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索