webpack|webpack 学习笔记之十一 hash chunkhash contenthash

一.hash是什么?
hash 是一种散列算法.
它可以将[任意长度的二进制数]据映射成[较短的固定长度的]二进制值.
它的原理很简单,所有的数据,不管是图片,文字,视频,文件等乱七八糟的东西.
丢给一个固定的hash算法,只要文件的内容不发生改变,那么计算出来的hash永远都是一样的.
大家最熟悉的hash算法莫过于 MD5 了.
二.hash在前端开发的过程中,起到了哪些特别的作用?
前端开发,不管是用什么框架,什么打包工具,最终运行的环境是浏览器.
浏览器是有缓存机制的.如果一个文件的文件名不发生变化,那么浏览器就会有很大的可能去缓存这个文件(cache-control:no-cache除外.)
有时候,浏览器的缓存也是一把双刃剑.比如我们的某个css文件的内容实际上是改了,但是由于文件名没改.
浏览器就认为这个文件没有发生变动,不去再次发生请求从服务器获取,而是从本地缓存里读取.会导致用户看到的文件并不是最新的.
所以,经常会看到这样的css代码.


通过给一个基本没啥作用的查询字符串结尾,让浏览器认为这是一个动态的请求,从而获得最新的css文件的目的.
webpack 提供的类似的功能,就叫做hash功能.
可以给打包出来的文件名,加上一串hash值,每次都可以生成一个新的文件名.
webpack 给文件名插入之 hash
webpack.config.js
const path = require('path') const { CleanWebpackPlugin } = require('clean-webpack-plugin')module.exports = { entry: { indexName: path.join(__dirname, 'index.js'), appFileName: path.join(__dirname, 'app.js') }, output: { path: path.join(__dirname, 'dist'), filename: '[name]_[hash].js' }, mode: 'development', plugins: [ new CleanWebpackPlugin() ] }

打包查看结果:
webpack|webpack 学习笔记之十一 hash chunkhash contenthash
文章图片
image.png 查看打包的输出结果
  • 整个项目的hash值是: e4b33a6c56df04dda9be
  • appFileName的hash值是: e4b33a6c56df04dda9be
  • indexName的hash值是: e4b33a6c56df04dda9be
现在仅仅修改 index.js 文件.
// index.js let i = 0

重新打包
webpack|webpack 学习笔记之十一 hash chunkhash contenthash
文章图片
image.png
  • 整个项目的hash值: 414410450aa6ab446bc3
  • appFileName的hash值是: 414410450aa6ab446bc3
  • indexName的hash值是: 414410450aa6ab446bc3
现在问题就来了, 我明明只改了 index.js 里的代码,app.js代码压根没动.但是它的hash还是变了.
hash是项目级别的.只要项目内部改动了任意一个位置,所有设置了 hash 的文件的hash值都会跟着一起发生改变.
(那些从来压根没改过的文件的hash也会跟着改变).这样的话,完全就不合理了.没变内容的文件如果hash也变了,文件
名就变了.文件变了,浏览器就需要重新下载这个文件,达不到缓存的作用了.
webpack 给文件插入之 chunkhash
chunkhash是针对entry的每一个入口文件,独立的hash。如果entry里面的其中一个文件内容改变,只会改变这个入口
文件build之后的文件名,而不会影响到其他文件。
webpack.config.js
const path = require('path') // import { CleanWebpackPlugin } from 'clean-webpack-plugin' // node.js 还不支持ES6的import模块导入语法. const { CleanWebpackPlugin } = require('clean-webpack-plugin')module.exports = { entry: { indexName: path.join(__dirname, 'index.js'), appFileName: path.join(__dirname, 'app.js') }, output: { path: path.join(__dirname, 'dist'), // filename: '[name]_[hash].js' filename: '[name]_[chunkhash].js' }, mode: 'development', module: { rules: [{ test: /\.(png|jpg|gif)$/, use: [{ loader: 'file-loader', options: { name: '[name]_[contenthash].[ext]' } }] }] }, plugins: [ new CleanWebpackPlugin() ] }

查看结果
webpack|webpack 学习笔记之十一 hash chunkhash contenthash
文章图片
image.png
  • 整个项目的 hash 值是: 9ec8f05fbffa71101b9c
  • appFileName 的 hash 值是: 420fbddeda08d6b1d3c0.
  • indexName 的 hash 值是: bdd32b0728173915f845
他们三个的hash值都不相同.
现在修改 app.js
let i = 0

查看结果:
webpack|webpack 学习笔记之十一 hash chunkhash contenthash
文章图片
image.png
  • 由于对于整个项目而言,的确有文件的内容被修改了,所以 hash 值从原来的 9ec8f05fbffa71101b9c 变成了 2bd51d157cc397ec1523. 在情理和意料之中.
  • appFileName 的 hash 值 : 49d983a60c15f9a92cb4 而原来的是 420fbddeda08d6b1d3c0 . 也在情理和意料之中,因为我们修改了 app.js 的代码 let i = 0
  • indexName 的 hash 仍然是原来的 bdd32b0728173915f845 , 没有改动过代码,所以还是原来的值.
webpack 给文件名插入之 contenthash
contenthash 顾名思义, 就是根据当前文件的内容,来计算hash值.
将非output的文件名设置hash或者chunkhash,比如(css,image等)都将无效,而且默认使用的是contenthash
比如:
rules: [{ test: /\.(png|jpg|gif)$/, use: [{ loader: 'file-loader', options: { name: '[name]_[hash].[ext]' // 按道理是当前项目的hash值. } }] }]

结果:
webpack|webpack 学习笔记之十一 hash chunkhash contenthash
文章图片
image.png 按道理来说,设置了hash,图片文件名应该和项目的hash一致.
但结果,它俩完全不一样,肉眼都可以一眼看出,起码长度都不一样.
webpack.config.js
rules: [{ test: /\.(png|jpg|gif)$/, use: [{ loader: 'file-loader', options: { // name: '[name]_[hash].[ext]' // 按道理是当前项目的hash值. name: '[name]_[chunkhash].[ext]' //Path variable [chunkhash] not implemented in this context: 282-8_[chunkhash].jpg } }] }]

配置费output文件成为chunkhash,直接报错.
//Path variable [chunkhash] not implemented in this context: 282-8_[chunkhash].jpg
压根就没实现这个hash的功能.
配置contenthash
rules: [{ test: /\.(png|jpg|gif)$/, use: [{ loader: 'file-loader', options: { // name: '[name]_[hash].[ext]' // 按道理是当前项目的hash值. // name: '[name]_[chunkhash].[ext]' //Path variable [chunkhash] not implemented in this context: 282-8_[chunkhash].jpg name: '[name]_[contenthash].[ext]' // 根据文件的内容,生成的hash } }] }]

结果:
webpack|webpack 学习笔记之十一 hash chunkhash contenthash
文章图片
image.png 发现和配置hash 的情况一致.也就是说,给jpg等静态资源配置hash默认就会转成contenthash.
总结:
  • hash [范围最大] 是针对整个项目的,如果把整个项目当做是一个文件(为什么非要是单个的1.txt就这么好理解成是文件了?),那么这个项目文件的内容发生改变(文件删除添加,文件内容修改),都会导致整个项目的hash值发生改变.
  • chunkhash [范围其次] 是根据当前入口文件最终打包出来的js文件.output. 当前依赖链中,有任意文件变动,都会改变这个hash值.
  • 而contenthash [范围最小] 就仅仅只是针对当前文件的内容.
这里说了一堆东西.到底想表达什么?
hash,chunkhash,contenthash,说白了,就是根据不同的范围,给最终生成的文件名里加一串字符串.(hash把整个项目当成一个文件; chunkhash把一个独立的entry个output当前一个文件(多个模块之间的依赖当成一个chunk); contenthash则是把单个文件当成是一个文件)
它们有一个共同的特点就是,最终它们都会是生成一个独立的文件,且在浏览器中,会有一个链接指向它们.
有链接指向它们,它们就能利用所谓的各种hash,来做缓存了.
一张图解:
webpack|webpack 学习笔记之十一 hash chunkhash contenthash
文章图片
image.png 【webpack|webpack 学习笔记之十一 hash chunkhash contenthash】码云

    推荐阅读