webpack 學習筆記之十一 hash chunkhash contenthash

一.hash是什么?

hash 是一種散列算法.

它可以將[任意長度的二進制數(shù)]據(jù)映射成[較短的固定長度的]二進制值.

它的原理很簡單,所有的數(shù)據(jù),不管是圖片,文字,視頻,文件等亂七八糟的東西.

丟給一個固定的hash算法,只要文件的內(nèi)容不發(fā)生改變,那么計算出來的hash永遠都是一樣的.

大家最熟悉的hash算法莫過于 MD5 了.


二.hash在前端開發(fā)的過程中,起到了哪些特別的作用?

前端開發(fā),不管是用什么框架,什么打包工具,最終運行的環(huán)境是瀏覽器.

瀏覽器是有緩存機制的.如果一個文件的文件名不發(fā)生變化,那么瀏覽器就會有很大的可能去緩存這個文件(cache-control:no-cache除外.)

有時候,瀏覽器的緩存也是一把雙刃劍.比如我們的某個css文件的內(nèi)容實際上是改了,但是由于文件名沒改.

瀏覽器就認為這個文件沒有發(fā)生變動,不去再次發(fā)生請求從服務器獲取,而是從本地緩存里讀取.會導致用戶看到的文件并不是最新的.

所以,經(jīng)常會看到這樣的css代碼.

<link rel="stylesheet" href="style.css?v=1.0">
<link rel="stylesheet" href="style.css?v=1.2">
<link rel="stylesheet" href="style.css?v=1.3">

通過給一個基本沒啥作用的查詢字符串結尾,讓瀏覽器認為這是一個動態(tài)的請求,從而獲得最新的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()
  ]
}

打包查看結果:

image.png

查看打包的輸出結果

  • 整個項目的hash值是: e4b33a6c56df04dda9be
  • appFileName的hash值是: e4b33a6c56df04dda9be
  • indexName的hash值是: e4b33a6c56df04dda9be

現(xiàn)在僅僅修改 index.js 文件.

// index.js
let i = 0

重新打包

image.png
  • 整個項目的hash值: 414410450aa6ab446bc3
  • appFileName的hash值是: 414410450aa6ab446bc3
  • indexName的hash值是: 414410450aa6ab446bc3

現(xiàn)在問題就來了, 我明明只改了 index.js 里的代碼,app.js代碼壓根沒動.但是它的hash還是變了.

hash是項目級別的.只要項目內(nèi)部改動了任意一個位置,所有設置了 hash 的文件的hash值都會跟著一起發(fā)生改變.

(那些從來壓根沒改過的文件的hash也會跟著改變).這樣的話,完全就不合理了.沒變內(nèi)容的文件如果hash也變了,文件

名就變了.文件變了,瀏覽器就需要重新下載這個文件,達不到緩存的作用了.


webpack 給文件插入之 chunkhash

chunkhash是針對entry的每一個入口文件,獨立的hash顽耳。如果entry里面的其中一個文件內(nèi)容改變,只會改變這個入口

文件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()
  ]
}

查看結果

image.png
  • 整個項目的 hash 值是: 9ec8f05fbffa71101b9c
  • appFileName 的 hash 值是: 420fbddeda08d6b1d3c0.
  • indexName 的 hash 值是: bdd32b0728173915f845

他們?nèi)齻€的hash值都不相同.

現(xiàn)在修改 app.js

let i = 0

查看結果:

image.png
  • 由于對于整個項目而言,的確有文件的內(nèi)容被修改了,所以 hash 值從原來的 9ec8f05fbffa71101b9c 變成了 2bd51d157cc397ec1523. 在情理和意料之中.
  • appFileName 的 hash 值 : 49d983a60c15f9a92cb4 而原來的是 420fbddeda08d6b1d3c0 . 也在情理和意料之中,因為我們修改了 app.js 的代碼 let i = 0
  • indexName 的 hash 仍然是原來的 bdd32b0728173915f845 , 沒有改動過代碼,所以還是原來的值.

webpack 給文件名插入之 contenthash

contenthash 顧名思義, 就是根據(jù)當前文件的內(nèi)容,來計算hash值.

將非output的文件名設置hash或者chunkhash,比如(css,image等)都將無效,而且默認使用的是contenthash

比如:

rules: [{
      test: /\.(png|jpg|gif)$/,
      use: [{
        loader: 'file-loader',
        options: {
          name: '[name]_[hash].[ext]' // 按道理是當前項目的hash值.
        }
      }]
    }]

結果:

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

壓根就沒實現(xiàn)這個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]' // 根據(jù)文件的內(nèi)容,生成的hash
        }
      }]
    }]

結果:

image.png

發(fā)現(xiàn)和配置hash 的情況一致.也就是說,給jpg等靜態(tài)資源配置hash默認就會轉成contenthash.


總結:

  • hash [范圍最大] 是針對整個項目的,如果把整個項目當做是一個文件(為什么非要是單個的1.txt就這么好理解成是文件了?),那么這個項目文件的內(nèi)容發(fā)生改變(文件刪除添加,文件內(nèi)容修改),都會導致整個項目的hash值發(fā)生改變.

  • chunkhash [范圍其次] 是根據(jù)當前入口文件最終打包出來的js文件.output. 當前依賴鏈中,有任意文件變動,都會改變這個hash值.

  • 而contenthash [范圍最小] 就僅僅只是針對當前文件的內(nèi)容.

這里說了一堆東西.到底想表達什么?

hash,chunkhash,contenthash,說白了,就是根據(jù)不同的范圍,給最終生成的文件名里加一串字符串.(hash把整個項目當成一個文件;chunkhash把一個獨立的entry個output當前一個文件(多個模塊之間的依賴當成一個chunk);contenthash則是把單個文件當成是一個文件)

它們有一個共同的特點就是,最終它們都會是生成一個獨立的文件,且在瀏覽器中,會有一個鏈接指向它們.

有鏈接指向它們,它們就能利用所謂的各種hash,來做緩存了.

一張圖解:

image.png

碼云

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市店枣,隨后出現(xiàn)的幾起案子鸯两,更是在濱河造成了極大的恐慌钧唐,老刑警劉巖匠襟,帶你破解...
    沈念sama閱讀 222,252評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件酸舍,死亡現(xiàn)場離奇詭異,居然都是意外死亡忽舟,警方通過查閱死者的電腦和手機淮阐,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評論 3 399
  • 文/潘曉璐 我一進店門浩姥,熙熙樓的掌柜王于貴愁眉苦臉地迎上來状您,“玉大人兜挨,你說我怎么就攤上這事暑劝】怕В” “怎么了?”我有些...
    開封第一講書人閱讀 168,814評論 0 361
  • 文/不壞的土叔 我叫張陵傅联,是天一觀的道長蒸走。 經(jīng)常有香客問我貌嫡,道長,這世上最難降的妖魔是什么别惦? 我笑而不...
    開封第一講書人閱讀 59,869評論 1 299
  • 正文 為了忘掉前任掸掸,我火速辦了婚禮扰付,結果婚禮上仁讨,老公的妹妹穿的比我還像新娘。我一直安慰自己禽翼,他們只是感情好族跛,可當我...
    茶點故事閱讀 68,888評論 6 398
  • 文/花漫 我一把揭開白布礁哄。 她就那樣靜靜地躺著,像睡著了一般夺脾。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上咧叭,一...
    開封第一講書人閱讀 52,475評論 1 312
  • 那天,我揣著相機與錄音吉挣,去河邊找鬼。 笑死睬魂,一個胖子當著我的面吹牛镀赌,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播喉钢,決...
    沈念sama閱讀 41,010評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼良姆,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起豹缀,我...
    開封第一講書人閱讀 39,924評論 0 277
  • 序言:老撾萬榮一對情侶失蹤慨代,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后氮惯,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體想暗,經(jīng)...
    沈念sama閱讀 46,469評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡说莫,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,552評論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了互婿。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,680評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡呛牲,死狀恐怖娘扩,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情畜侦,我是刑警寧澤躯保,帶...
    沈念sama閱讀 36,362評論 5 351
  • 正文 年R本政府宣布途事,位于F島的核電站,受9級特大地震影響义图,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜碱工,卻給世界環(huán)境...
    茶點故事閱讀 42,037評論 3 335
  • 文/蒙蒙 一怕篷、第九天 我趴在偏房一處隱蔽的房頂上張望酗昼。 院中可真熱鬧廊谓,春花似錦蒸痹、人聲如沸呛哟。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,519評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽借帘。三九已至蜘渣,卻和暖如春蔫缸,著一層夾襖步出監(jiān)牢的瞬間际起,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,621評論 1 274
  • 我被黑心中介騙來泰國打工校翔, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留灾前,地道東北人。 一個月前我還...
    沈念sama閱讀 49,099評論 3 378
  • 正文 我出身青樓蔫敲,卻偏偏與公主長得像炭玫,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子吞加,可洞房花燭夜當晚...
    茶點故事閱讀 45,691評論 2 361

推薦閱讀更多精彩內(nèi)容