webpack hash chunkhash contenthash浅析
1.基本概念
bundle 和 chunk是什么?
官网解释:bundle由chunk组成,其中有几种类型(入口 entry chunk child chunk)。通常,chunk会直接对所输出的bundle。但是有些配置并不会产生一对一的关系。
个人理解:chunk就是代码块的意思。多个chunk合在一起,就是bundle,一个bundle可以理解成一个大的js打包后生成的文件,而多个bundle里面的公共代码,或者需要按需加载的代码,就会拆成不同的chunk.
module:就是模块,在webpack中一个模块对应一个文件。webpack会从entry开始,递归地找出所有依赖的模块。
类似于 我如果只有一个入口文件,入口文件中也没有任何依赖,只有本文件中的代码,那么这个文件就即是一个module,也是一个chunk,还是一个bundle。
同上,如果我只有一个入口文件,入口文件index.js中引入了react react-dom,如果我们不拆包,那么就是3个module,一个chunk,一个bundle,如果我们把react的东西拆出去打成vendor.js,那么就是3个module,2个chunk,一个bundle。
hash:在 webpack 一次构建中会产生一个 compilation 对象,该 hash 值是对 compilation 内所有的内容计算而来的。
chunkhash:每一个 chunk 都根据自身的内容计算而来。它根据不同的入口文件(Entry)进行依赖文件解析、构建对应的chunk,生成对应的哈希值。
contenthash:根据文件内容计算而来。
2.具体应用
文件指纹 主要是在生成文件的时候用到包括 hash chunkhash contenthash,一般会在设置output filename,以及css文件名的时候使用到。
1.使用hash
2.使用chunkhash
我们在生产环境里把一些公共库和程序入口文件区分开,单独打包构建,接着我们采用chunkhash的方式生成哈希值,那么只要我们不改动公共库的代码,就可以保证其哈希值不会受影响。
3.使用contenthash
但是
webpack中是如何进行文件内容计算的呢? 是根据moduleId.content来计算的,然后生成对应的hash值。
问题又来了,moduleId是怎么来的呢?
eg:module.id === require.resolve('./file.js');
它是根据模块排序方法计算的,这是因为每个 module.id 会默认地基于解析顺序(resolve order)进行增量(module是全局的,是为了不同的入口文件,引入同一个module时可以使用缓存,而不必打重复的包)。也就是说,当解析顺序发生变化,ID 也会随之改变,极其不稳定。
解决办法 固定moduleId,使用NamedModulesPlugin 插件来固定moduleId.
还有一个Webpack 内部维护了一个自增的 id,每个 chunk 都有一个 id。所以entry新增或者减少入口文件时,也会导致 contenthash变化,因为对应的chunkId变了,解决办法就是固定chunkId。使用HashedModuleIdsPlugin插件。
总结下来,hash受所有代码影响,只要有变化,hash就变了。
chunkhash,受到它自身chunk内容的影响,以及chunkId moduleId的影响。
contenthash,受到它自身文件内容的影响,以及chunkId moduleId的影响。
他们受影响的范围,依次递减。
3.结尾
contenthash在webpack4 之前都只能在css上使用,并不能在js上使用,并且现在也只是在production 环境上才能使用,开发环境上我们更多地希望没有缓存,所以会给打包出来的文件,都使用hash值