静态资源缓存策略到底该怎么配才不会出问题?

司空朝炜 阅读 22

我在部署一个 React 项目时,发现每次更新代码后用户还是看到旧内容,怀疑是缓存没处理好。我试过在 nginx 里加了 Cache-Control: max-age=31536000 给静态资源,但好像只有第一次生效,后续改了 JS 文件名没变,浏览器就直接用缓存了。

现在打包后的文件名是固定的,比如 main.js,是不是应该用 contenthash 来命名?但我不确定 Webpack 怎么配置才能让 HTML 引用带 hash 的文件,同时避免 HTML 被长期缓存。有没有一套稳妥的缓存策略能兼顾性能和更新?

module.exports = {
  output: {
    filename: 'static/js/[name].[contenthash:8].js',
    chunkFilename: 'static/js/[name].[contenthash:8].chunk.js'
  },
  optimization: {
    runtimeChunk: 'single'
  }
};
我来解答 赞 6 收藏
二维码
手机扫码查看
2 条解答
UX诗晴
UX诗晴 Lv1
遇到这种情况,确实得好好调整一下静态资源的缓存策略。你说的问题主要有两方面:一是静态资源的长期缓存,二是确保 HTML 文件不过度缓存,以便引用最新的静态资源文件。

首先,关于静态资源的缓存,你的做法是正确的,使用 contenthash 来生成文件名是个好主意。这样每次内容变化时,文件名也会变化,浏览器就会重新下载最新的资源而不是使用缓存。你已经在 Webpack 配置中设置了 filenamechunkFilename 使用 contenthash,这一步没问题。

接下来,你需要确保 HTML 文件不被缓存或者至少在内容更新时能够及时刷新。可以在 Nginx 配置中为 HTML 文件设置较短的缓存时间或者不缓存,例如:

location / {
try_files $uri $uri/ /index.html;
add_header Cache-Control "no-cache, no-store, must-revalidate";
}


这样可以确保每次请求 HTML 文件时,浏览器都会从服务器获取最新版本,而不会使用缓存。

最后,Webpack 打包生成的带有 contenthash 的文件名,你需要在 HTML 中正确引用。如果你使用的是 HtmlWebpackPlugin,它会自动处理这个问题,只要确保配置正确即可。如果没有使用,你可能需要借助一些插件,比如 html-webpack-plugin,来动态注入带有 contenthash 的文件名到 HTML 中。基本配置如下:

const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
// 其他配置...
plugins: [
new HtmlWebpackPlugin({
template: './public/index.html',
filename: 'index.html',
}),
],
};


这样配置后,HtmlWebpackPlugin 会根据打包生成的文件名自动更新 HTML 中的引用。

官方文档里说得很清楚,合理的缓存策略对于前端应用的性能至关重要,但也要确保在内容更新时能够及时反映给用户。希望这些信息对你有帮助。
点赞
2026-03-23 18:15
Mr.利娟
Mr.利娟 Lv1
你配置 contenthash 是对的,但关键是没解决 HTML 引用的问题。Webpack 需要配合 html-webpack-plugin 才能自动把带 hash 的文件名注入到 HTML 里。

先改 Webpack 配置:

// webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
output: {
filename: 'static/js/[name].[contenthash:8].js',
chunkFilename: 'static/js/[name].[contenthash:8].chunk.js'
},
optimization: {
runtimeChunk: 'single'
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
// 每次构建重新生成,不缓存 HTML
inject: 'body'
})
]
};


这样打包后 HTML 里的 script src 会自动变成类似 main.a1b2c3d4.js 这种带 hash 的。

然后 Nginx 配置要区分对待:

# 静态资源长期缓存
location ~* .(js|css|png|jpg|woff2?)$ {
expires 1y;
add_header Cache-Control "public, no-transform";
}

# HTML 不缓存,每次都问服务器
location ~* .html$ {
expires -1s;
add_header Cache-Control "no-store, no-cache, must-revalidate";
}


核心逻辑就是:JS 文件名变了(contenthash),所以浏览器会重新请求;HTML 文件名不变,但通过设置 no-cache 强制浏览器每次都拿最新的,HTML 里的引用自然就是最新带 hash 的文件了。

还有一个坑要注意:如果用了 chunkFilename,异步加载的 chunk 也得配好缓存,上面 Nginx 正则已经覆盖到了。

代码放这了,有问题再问。
点赞
2026-03-20 10:09