前言javascript
浏览器为了优化体验,会有缓存机制。若是浏览器判断当前资源没有更新,就不会去服务端下载,而是直接使用本地资源。在webpack的构建中,咱们一般使用给文件添加后缀值来更名以及提取公共代码到不会改变的lib包中来解决新资源缓存问题。css
hash & chunkhash & contenthashjava
咱们在webpack构建中经过配置filenames来决定输出的文件名,好比咱们的配置以下webpack
则打包出来的目录以下web
能够看到, 打包出来的js名称对应的就是这样的规则,这里之因此name对应的是main, 是由于咱们没有指定entry的key值,默认是main,不然就是相对于的key值。浏览器
在上面,咱们看到,咱们配置的hash值,而后打包出的是一个长串字符串,这边的的长度咱们能够指定,好比配置为缓存
entry: './src/index.js', output: { filename: '[name].[hash:8].js', path: path.resolve(__dirname, 'dist') }
这样打包出来的就是8位的字符串,咱们看到这边main模块打包出的和slove模块打包出的hash值是同样的,这个是什么缘由呢?咱们先来看一下官方对于hash的解释ruby
模块标识符(module identifier)的 hash
这个不是很好理解,什么叫作模块标识符呢?咱们知道对于webpack来讲,它是一个打包编译的过程,也就是一个 compilation的过程,这个标识符,标识的就是这个打包的过程。这样就很好解释了模块标识符的概念就是在相同编译打包过程当中的模块所共有的标识符,也就是说同一过程产出的产物的hash值都是同样的,也就解释了上面的过程。bash
可是这样会有很大的问题,由于咱们不想改变css模块而去影响到js打包出来的名称,这样不利于咱们去作缓存。那该怎么去解决这样的问题呢?ide
这时候咱们就须要chunkhash出场来解决问题了,咱们先来看一下官方对于chunkhash的解释
chunk 内容的 hash
咱们知道chunk指代的是模块,顾名思义,chunkhash就是模块的hash,也就是根据模块内容计算的hash值。那这边咱们css模块的修改和js模块就没有关系,咱们看一下使用chunkhash打包出来的结果,配置以下:
entry: { main: './src/index.js', slove: './src/slove.js' }, output: { filename: '[name].[chunkhash].js', path: path.resolve(__dirname, 'dist') }
这时候打包出来的目录如图所示:
这时候咱们看到main模块与slove模块的hash值是不一样的,这样咱们修改main中的内容就不会修改slove的名称,slove的缓存就能够继续使用了。可是,这时候咱们发现,main模块中的css文件和js文件的hash值是相同的。若是咱们修改了js的内容,css的打包名称也会改变,这是咱们不须要的,因此咱们怎么解决这个问题呢。
从名称上咱们能够知道,它是根据文件内容来定义hash值得,因此咱们就可使用插件extract-text-webpack-plugin定义的contenthash来打包。配置以下:
new MiniCssExtractPlugin({ filename: "[name].[contenthash].css" })
这样打包出来的结果是:
总结的一个方法:
const addHash = fname => { var r = fname; if (IS_DEV) return r; const name = "[name]"; const index = fname.lastIndexOf(name); if (index !== -1) { const suffix = fname.substring(index + name.length); let hash = 'hash' if (suffix === '.js') { hash = 'chunkhash' } else if (suffix === '.css') { hash = 'contenthash' } r = fname.replace(name + suffix, `${name}.[${hash}:8]${suffix}`); } return r; };
引入的例子以下图: