3、Vite缓存策略:依赖预构建缓存、浏览器缓存策略、文件哈希缓存

聊到Vite的缓存,我得先坦白一件事。我刚从Webpack切换到Vite那会儿,总觉得它「偷偷摸摸」干了很多事。尤其是第一次启动时那个 Pre-bundling dependencies 的提示,我一度以为它卡住了。后来才明白,这其实是Vite最聪明的设计之一。

说白了,Vite的缓存策略分三层:依赖预构建缓存浏览器HTTP缓存文件哈希缓存。这三层各司其职,又互相配合。我们一层层拆开看。

3.1 依赖预构建缓存:为什么第一次启动那么慢?

你想想看,Vite在开发模式下用的是ES Module。但node_modules里的依赖,很多还是CommonJS格式,或者有大量内部模块引用。浏览器直接加载?不行的。

所以Vite做了个预处理:把依赖统一转换成ES Module,并合并成少量文件。这个过程叫「依赖预构建」。

预构建的结果会缓存到哪里?默认在 node_modules/.vite 目录下。我习惯把这个目录叫做「Vite的私房钱」。

缓存判断依据:

  • package-lock.jsonyarn.lock 是否变化
  • vite.config.js 中的 optimizeDeps 配置是否变化
  • Node.js 版本是否变化

只要这些没变,Vite就不会重新预构建。所以第二次启动时,你会感觉快得像闪电。

我的小技巧: 如果你改了某个依赖的版本,但锁文件没更新(比如直接改了node_modules里的文件),Vite不会自动重新预构建。这时候可以手动删除 node_modules/.vite 目录,或者运行 npx vite --force。我曾经因为这个排查了半天,后来学乖了。

3.2 浏览器缓存策略:304 Not Modified 的秘密

开发模式下,Vite返回的静态资源都带着特殊的HTTP头。我截个关键配置给你看:

// Vite 内部对静态资源的响应头设置
// 对于 JS/TS 模块
Cache-Control: no-cache
// 对于 CSS、图片等静态资源
Cache-Control: max-age=31536000, immutable

为什么JS模块要用 no-cache?因为开发时你随时可能改代码。如果浏览器缓存了旧的JS模块,你改了代码页面却没反应,那得多崩溃。

但CSS和图片就不一样了。这些资源很少在开发时频繁改动,所以Vite允许浏览器缓存一年。嗯,这里要注意:如果改了CSS文件,Vite会通过模块热更新(HMR)直接推送新样式,不需要走HTTP缓存

我曾经踩过的坑: 有次我在开发环境调试一个图片加载问题,改了图片文件但页面始终显示旧的。查了半天才发现,浏览器缓存了这张图。虽然Vite设置了 immutable,但浏览器还是优先用自己的缓存。解决办法:打开开发者工具,勾选「Disable cache」。

3.3 文件哈希缓存:生产构建的指纹

生产环境就完全不一样了。Vite会把所有静态资源文件名加上哈希值。比如:

// 构建前
src/main.js
src/App.vue

// 构建后
assets/main.a1b2c3d4.js
assets/App.5e6f7g8h.js

这个哈希值是根据文件内容计算出来的。文件内容变了,哈希就变。浏览器发现URL变了,自然会重新请求新文件。

我个人的习惯是,在 vite.config.js 里这样配置:

// vite.config.js
export default defineConfig({
  build: {
    rollupOptions: {
      output: {
        // 自定义哈希长度,默认是8位
        entryFileNames: 'assets/[name].[hash:8].js',
        chunkFileNames: 'assets/[name].[hash:8].js',
        assetFileNames: 'assets/[name].[hash:8][extname]'
      }
    }
  }
})

哈希长度8位够用吗?说实话,对于绝大多数项目足够了。哈希碰撞的概率比中彩票还低。

3.4 缓存策略对比表

缓存类型 作用阶段 缓存位置 失效条件
依赖预构建缓存 开发启动 node_modules/.vite 锁文件、配置、Node版本变化
浏览器HTTP缓存 开发运行 浏览器内存/磁盘 响应头 no-cache 或手动禁用
文件哈希缓存 生产构建 CDN/浏览器 文件内容变化导致哈希改变

3.5 避坑指南:缓存引发的诡异问题

我遇到过最离谱的一次:同事说他的页面样式不对,我过去一看,他的浏览器里还加载着昨天构建的CSS文件。哈希没变,但内容变了。为什么?因为他在构建时用了 --watch 模式,但没清浏览器缓存。

所以我的建议是:

  • 开发时:养成按 Ctrl+Shift+R 强制刷新页面的习惯
  • 构建时:确保每次构建都生成新的哈希值
  • 部署时:CDN的缓存策略要配合文件哈希,设置 immutable

一个小工具推荐: 我常用 vite-plugin-inspect 这个插件,可以直观看到每个模块的缓存状态。安装后访问 http://localhost:5173/__inspect/,就能看到Vite内部是怎么处理缓存的。

总结一下:Vite的缓存策略说白了就是「该快的时候快,该新的时候新」。开发时依赖预构建缓存让你秒启项目,浏览器缓存配合HMR让你实时看到修改。生产时文件哈希缓存让用户永远拿到最新代码,同时还能利用CDN加速。

嗯,缓存这东西,用好了是神器,用不好就是坑。希望我这十几年的经验能帮你少走些弯路。