webpack 中,hash、chunkhash、contenthash 的區別是什麼?

Webpack 有非常多的概念,很多名詞長得都差不多。我把這些分散在文檔和教程裏的內容總結起來,寫了一份 webpack 中的易混淆知識點,目前看是全網獨一份,大家可以加個收藏,方便以後檢索和學習。

全集鏈接 ➡️ webpack 易混淆知識點

首先來個背景介紹,哈希一般是結合 CDN 緩存來使用的。如果文件內容改變的話,那麼對應文件哈希值也會改變,對應的 HTML 引用的 URL 地址也會改變,觸發 CDN 服務器從源服務器上拉取對應數據,進而更新本地緩存。

4.1 hash

hash 計算是跟整個項目的構建相關,我們做一個簡單的 demo。

沿用案例 1 的 demo 代碼,文件目錄如下:

src/
├── index.css
├── index.html
├── index.js
└── utils.js

webpack 的核心配置如下(省略了一些 module 配置信息):

{
    entry: {
        index: "../src/index.js",
        utils: '../src/utils.js',
    },
    output: {
        filename: "[name].[hash].js",  // 改爲 hash
    },
    
    ......
    
    plugins: [
        new MiniCssExtractPlugin({
            filename: 'index.[hash].css' // 改爲 hash
        }),
    ]
}

生成的文件名如下:

我們可以發現,生成文件的 hash 和項目的構建 hash 都是一模一樣的。

4.2 chunkhash

因爲 hash 是項目構建的哈希值,項目中如果有些變動,hash 一定會變,比如說我改動了 utils.js 的代碼,index.js 裏的代碼雖然沒有改變,但是大家都是用的同一份 hash。hash 一變,緩存一定失效了,這樣子是沒辦法實現 CDN 和瀏覽器緩存的。

chunkhash 就是解決這個問題的,它根據不同的入口文件(Entry)進行依賴文件解析、構建對應的 chunk,生成對應的哈希值。

我們再舉個例子,我們對 utils.js 裏文件進行改動:

export function square(x) {
    return x * x;
}

// 增加 cube() 求立方函數
export function cube(x) {
    return x * x * x;
}

然後把 webpack 裏的所有 hash 改爲 chunkhash:

{
    entry: {
        index: "../src/index.js",
        utils: '../src/utils.js',
    },
    output: {
        filename: "[name].[chunkhash].js", // 改爲 chunkhash
    },
          
    ......
    
    plugins: [
        new MiniCssExtractPlugin({
            filename: 'index.[chunkhash].css' // // 改爲 chunkhash
        }),
    ]
}

構建結果如下:

我們可以看出,chunk 0 的 hash 都是一樣的,chunk 1 的 hash 和上面的不一樣。

假設我又把 utils.js 裏的 cube() 函數去掉,再打包:

對比可以發現,只有 chunk 1 的 hash 發生變化,chunk 0 的 hash 還是原來的。

4.3 contenthash

我們更近一步,index.js 和 index.css 同爲一個 chunk,如果 index.js 內容發生變化,但是 index.css 沒有變化,打包後他們的 hash 都發生變化,這對 css 文件來說是一種浪費。如何解決這個問題呢?

contenthash 將根據資源內容創建出唯一 hash,也就是說文件內容不變,hash 就不變。

我們修改一下 webpack 的配置:

{
    entry: {
        index: "../src/index.js",
        utils: '../src/utils.js',
    },
    output: {
        filename: "[name].[chunkhash].js",
    },
      
    ......
    
    plugins: [
        new MiniCssExtractPlugin({
            filename: 'index.[contenthash].css' // 這裏改爲 contenthash
        }),
    ]
}

我們對 index.js 文件做了 3 次修改(就是改了改 log 函數的輸出內容,過於簡單就先不寫了),然後分別構建,結果截圖如下:

我們可以發現,css 文件的 hash 都沒有發生改變。

4.4 一句話總結:

hash 計算與整個項目的構建相關;

chunkhash 計算與同一 chunk 內容相關;

contenthash 計算與文件內容本身相關。




最後推薦一下我的個人公衆號:「滷蛋實驗室」,平時會分享一些前端技術和數據分析的內容,大家感興趣的話可以關注一波:


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章