Open jyzwf opened 5 years ago
现代前端打包,大多数是基于 webpack 来打包,打包就会涉及到文件的命名,文件的名称又会涉及到浏览器的缓存,所以如何命名文件很重要。
在打包过程中,我们常常会加上一个 hash 值来表示这个文件的唯一性。webpack 中提供了 3 种 hash,下面就来聊聊这些个 hash 。
首先提供一个 react 项目,目录结构如下:
其中 webpack 配置如下:
const HtmlWebpackPlugin = require("html-webpack-plugin"); const { CleanWebpackPlugin } = require("clean-webpack-plugin"); const MiniCssExtractPlugin = require("mini-css-extract-plugin"); const webpack = require("webpack"); const path = require("path"); module.exports = { mode: "production", entry: "./src/index.jsx", devtool: "inline-source-map", output: { filename: "[name].js", path: path.resolve(__dirname, "dist"), chunkFilename: "[name].js", }, module: { rules: [ { test: /\.jsx?$/, exclude: /node_modules/, use: "babel-loader", }, { test: /\.css$/, use: [ { loader: MiniCssExtractPlugin.loader, options: { hmr: process.env.NODE_ENV === "development", }, }, "css-loader", ], }, ], noParse: /^(react|react-dom|lodash)$/, }, devServer: { contentBase: "./dist", port: 3000, quiet: true, }, resolve: { extensions: [".js", ".jsx", ".json"], }, optimization: { splitChunks: { cacheGroups: { vendors: { name: "chunk-vendors", test: /[\\/]node_modules[\\/]/, priority: -10, chunks: "initial", }, common: { name: "chunk-common", minChunks: 2, priority: -20, chunks: "initial", reuseExistingChunk: true, }, commonAsync: { name: "chunk-common-async", minChunks: 2, priority: -15, chunks: "async", reuseExistingChunk: true, }, }, }, }, plugins: [ new CleanWebpackPlugin(), new HtmlWebpackPlugin({ template: "./src/index.ejs", }), new webpack.ProgressPlugin(), // new webpack.HotModuleReplacementPlugin(), new MiniCssExtractPlugin({ filename: "[name].css", }), ], };
关于 splitChunks 参见 聊一聊Code Splitting,上面我们使用了 mini-css-extract-plugin 来提取 css 文件。
先来看下 不使用 hash 的情况打包结果:
可以看出,文件名是固定的,这样如果我们修改了一些内容,如果使用了浏览器的缓存,那么下次请求这些文件的时候,会不去请求新的打包文件,从而造成文件不更新。
现在将上面的 filename 改成 [name].[hash].js/css,在看下打包情况:
filename
[name].[hash].js/css
可以看出,所有的文件使用了 同一个 hash 值,现在来修改 Hello/index.jsx 文件
Hello/index.jsx
hash 值变了,由于 hash 是跟整个项目的构建相关,只要项目里有文件更改,整个项目构建的hash值都会更改,并且全部文件都共用相同的hash值。这样对于类如 chunk-vendors 文件来说是不可取的,因为这些文件是不会经常改变的,如果使用了 hash,那么浏览器的缓存对于 一些 npm 包文件来说是无效的。
上面讲到了 hash 会在每次打包的时候改变值,这样对于一些没有变的文件,类如 react、react-dom ,完全起不到缓存效果。所以 webpack 又提供了一个 chunkhash。chunkhash 根据不同的入口文件(Entry)进行依赖文件解析、构建对应的 chunk,生成对应的哈希值。我们在生产环境里把一些公共库和程序入口文件区分开,单独打包构建,接着我们采用chunkhash的方式生成哈希值,那么只要我们不改动公共库的代码,就可以保证其哈希值不会受影响。
react
react-dom
chunkhash
chunk
将上面的 filename 改成 [name].[chunkhash].js/css:
[name].[chunkhash].js/css
chunk-vendors 和 main 的hash 值不一样了,OK,我们实现了 公共库的一个 hash 不变,利于 浏览器对于 公共库的一个缓存。
现在继续修改 Hello/index.jsx 文件:
可以看出,即使我们修改了 代码,公共库的 hash 没有变。但我们也注意到了,css 的hash 和 main 的hash 一样,即使我只改变了 js 文件,css 文件也跟着改变了。这是由于主入口的 js 和 css 被打包在了 同一个 模块,所以公用了一个 hash 值。这样对于 css 来说也是不可取的,接下来就该 contenthash 出场了。
contenthash
我们可以使用 mini-css-extract-plugin 提供的功能来解决上述的问题,将上面的 filename 改成 [name].[contenthash].js/css:
mini-css-extract-plugin
[name].[contenthash].js/css
修改下 js 文件:
ok,css 文件没有变,下面接着试下修改 css 文件:
css 与 js 的修改基本都不影响其他文件,great。
ps:如有不当,欢迎交流 😊😊
webpack中的hash、chunkhash、contenthash区别 output.filename 缓存
现代前端打包,大多数是基于 webpack 来打包,打包就会涉及到文件的命名,文件的名称又会涉及到浏览器的缓存,所以如何命名文件很重要。
在打包过程中,我们常常会加上一个 hash 值来表示这个文件的唯一性。webpack 中提供了 3 种 hash,下面就来聊聊这些个 hash 。
准备工作
首先提供一个 react 项目,目录结构如下:
其中 webpack 配置如下:
关于 splitChunks 参见 聊一聊Code Splitting,上面我们使用了 mini-css-extract-plugin 来提取 css 文件。
不使用 hash
先来看下 不使用 hash 的情况打包结果:
可以看出,文件名是固定的,这样如果我们修改了一些内容,如果使用了浏览器的缓存,那么下次请求这些文件的时候,会不去请求新的打包文件,从而造成文件不更新。
使用 hash
现在将上面的
filename
改成[name].[hash].js/css
,在看下打包情况:可以看出,所有的文件使用了 同一个 hash 值,现在来修改
Hello/index.jsx
文件hash 值变了,由于 hash 是跟整个项目的构建相关,只要项目里有文件更改,整个项目构建的hash值都会更改,并且全部文件都共用相同的hash值。这样对于类如 chunk-vendors 文件来说是不可取的,因为这些文件是不会经常改变的,如果使用了 hash,那么浏览器的缓存对于 一些 npm 包文件来说是无效的。
chunkhash
上面讲到了 hash 会在每次打包的时候改变值,这样对于一些没有变的文件,类如
react
、react-dom
,完全起不到缓存效果。所以 webpack 又提供了一个chunkhash
。chunkhash
根据不同的入口文件(Entry)进行依赖文件解析、构建对应的chunk
,生成对应的哈希值。我们在生产环境里把一些公共库和程序入口文件区分开,单独打包构建,接着我们采用chunkhash的方式生成哈希值,那么只要我们不改动公共库的代码,就可以保证其哈希值不会受影响。将上面的
filename
改成[name].[chunkhash].js/css
:chunk-vendors 和 main 的hash 值不一样了,OK,我们实现了 公共库的一个 hash 不变,利于 浏览器对于 公共库的一个缓存。
现在继续修改
Hello/index.jsx
文件:可以看出,即使我们修改了 代码,公共库的 hash 没有变。但我们也注意到了,css 的hash 和 main 的hash 一样,即使我只改变了 js 文件,css 文件也跟着改变了。这是由于主入口的 js 和 css 被打包在了 同一个 模块,所以公用了一个 hash 值。这样对于 css 来说也是不可取的,接下来就该
contenthash
出场了。contenthash
我们可以使用
mini-css-extract-plugin
提供的功能来解决上述的问题,将上面的filename
改成[name].[contenthash].js/css
:修改下 js 文件:
ok,css 文件没有变,下面接着试下修改 css 文件:
css 与 js 的修改基本都不影响其他文件,great。
参考
webpack中的hash、chunkhash、contenthash区别 output.filename 缓存