共计 1577 个字符,预计需要花费 4 分钟才能阅读完成。
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 值