如何为React Suspense懒加载拆分的代码块实现缓存破坏?
当前使用的HtmlWebpackPlugin的hash: true配置,只会给HTML静态直接引用的入口资源的URL追加全局构建hash查询参数。而React懒加载拆分出来的chunk是应用运行时动态请求的,根本不会经过HtmlWebpackPlugin的URL处理流程,因此不会自动带上缓存破坏参数,最终被浏览器长期缓存。
1. 调整Webpack输出配置
废弃靠查询参数做缓存破坏的思路,直接把内容hash嵌入所有输出文件的文件名中,这也是Webpack官方推荐的长期缓存实现方案。在webpack.config.js的output字段做如下配置:
output: { // 主入口bundle的命名规则:文件名带内容hash filename: '[name].[contenthash].bundle.js', // 动态拆分的懒加载chunk的命名规则:同样带内容hash chunkFilename: '[name].[contenthash].chunk.js', // 必须配置正确的公共路径,否则动态chunk加载路径会出错 publicPath: '/' }
其中[contenthash]是根据文件内容生成的哈希值:只有当文件本身的代码发生变化时,哈希值才会改变;代码不变则哈希值保持一致,能最大化提升缓存命中率。
注意:配置文件名哈希时不要使用
[hash],这是整个构建过程的全局哈希,哪怕修改了一个不相关的文件,所有输出文件的哈希都会变化,会大幅降低缓存命中率,一定要使用[contenthash]实现和文件内容绑定的哈希规则。
2. 简化HtmlWebpackPlugin配置
移除之前的hash: true配置项:
plugins: [ new HtmlWebpackPlugin({ template: path.resolve(__dirname, 'src', 'public', 'index.html'), // 删除原有 hash: true 配置 }), // 其他插件配置... ]
配置完成后,HtmlWebpackPlugin会自动读取output中带哈希值的真实文件路径,注入到生成的index.html中,无需额外追加查询参数。
3. 匹配服务端缓存规则
为了让整套缓存破坏逻辑正常生效,需要配合服务端的响应头配置:
- 对所有带contenthash的静态资源(js、css、图片等):设置长缓存规则,例如
Cache-Control: public, max-age=31536000, immutable。因为文件名自带内容哈希,一旦文件内容变化就是全新的文件路径,完全不用担心客户端拿到旧缓存。 - 对
index.html文件:设置禁止缓存规则,例如Cache-Control: no-cache,保证客户端每次拿到的都是最新的HTML,能正确引用最新哈希值的入口资源。
配置完成后,不管是主入口bundle,还是通过React.lazy拆分出的动态chunk,都会在文件名中携带对应内容的哈希值。只要代码有更新,对应文件的哈希值就会变化,客户端加载时会自动请求全新的文件路径,彻底解决旧chunk被客户端缓存、无法获取最新版本的问题。比如原来固定路径的/main.bundle.js会变成/main.a1b2c3d4.bundle.js,用户中心页对应的懒加载chunk,会生成类似user-center.4e5f6g7h.chunk.js的文件路径。
内容的提问来源于stack exchange,提问作者Chuck Waggon

