天天看點

前端webpack術語|module、chunk、bundle的差別?

作者:尚矽谷教育

module、chunk、bundle都是webpack中的術語。那麼他們究竟是什麼呢?對于這3個名詞感覺他們都在說打封包件,但是具體細節的差別呢?希望通過本文大家對此有細緻的了解。

一、術語的解釋

1. module是什麼?

官方概念:Module 是離散功能塊,相比于完整程式提供了更小的接觸面。精心編寫的子產品提供了可靠的抽象和封裝界限,使得應用程式中每個子產品都具有條理清楚的設計和明确的目的。

module其實就是一個檔案或者檔案内通過import等方式引用代碼塊或第三方等均可認為是一個module,也就是說任何一個可以被導入導出的檔案都是一個子產品。

2. chunk是什麼?

官方概念:Chunk 此 webpack 特定術語在内部用于管理捆綁過程。輸出束(bundle)由塊組成,其中有幾種類型(例如 entry 和 child )。通常,塊 直接與 輸出束 (bundle)相對應,但是,有些配置不會産生一對一的關系。

當我們寫的 module 源檔案傳到 webpack 進行打包時,webpack 會根據檔案引用關系生成 chunk 檔案,webpack 會對這個 chunk 檔案進行一些操作。

3. bundle是什麼?

官方概念:bundle 由許多不同的子產品生成,包含已經經過加載和編譯過程的源檔案的最終版本。

webpack 處理好 chunk 檔案後,最後會輸出 bundle 檔案,這個 bundle 檔案包含了經過加載和編譯的最終源檔案,是以它可以直接在浏覽器中運作。通常我們會弄混這兩個概念,以為Chunk就是Bundle,Bundle就是我們最終輸出的一個或多個打封包件。大多數情況下,一個Chunk會生産一個Bundle。

二、案例示範

從定義來說:

  • “子產品”(module)的概念大家都比較熟悉,如 CommonJS 子產品、AMD、ES6 Modules 子產品。
  • chunk 表示打包的時候産生的子產品,由他來組成 bundle。
  • 打包完成的源代碼。

我們現在就隻建立一個webpack配置,步驟如下:

1.建立一個空檔案夾,并且在目前檔案夾下打開cmd。

2.npm init -y 生成package.json。

3.執行 npm i webpack webpack-cli -D, 安裝webpack的包。

4.建立src,在src内部建立index.html、index.js、index.css、utils.js、common.js,并且編寫内部代碼。

5.在項目根目錄建立 webpack.config.js。

6.直接在cmd中運作 webpack。

前端webpack術語|module、chunk、bundle的差別?

1.目錄結構

src

├── index.css

├── index.html # 這個是 HTML 模闆代碼

├── index.js

├── common.js

└── utils.js

webpack.config.js

package.json

2.各檔案代碼内容

index.html

<body>

<div class="box">Hello</div>

</body>

index.css

body {

background-color: pink;

}

.box {

font-size: 24px;

font-weight: bold;

}

index.js

import "./index.css";

const { log } = require("./common");

log("webpack");

common.js

module.exports = {

log: (msg) => {

console.log(msg);

},

};

utils.js

export function add(x, y) {

return x + y;

}

3.webpack的配置

// 在配置檔案中,使用的子產品化規範是 commonjs

const path = require("path");

// 引入編譯html的插件

const HTMLWebpackPlugin = require("html-webpack-plugin");

// 引入抽離css檔案的插件

const MiniCssExtractPlugin = require("mini-css-extract-plugin");

const options = {

stats: {

chunks: true,

ids: true,

hash: true,

},

optimization: {

chunkIds: "natural",

},

// 模式

// development 開發模式 production 生産模式

mode: "development",

// 入口子產品的聲明

entry: {

index: "./src/index.js",

utils: "./src/utils.js",

},

// 輸出目錄

output: {

// ./dist

path: path.resolve(__dirname, "dist"),

// 輸出 index.js 和 utils.js

filename: "./js/[name].bundle-[hash].js",

// 每次編譯的時候把上一次的内容給清空

clean: true,

},

// loader - 可以讓webpack解析非js的其他子產品

module: {

// 解析規則

rules: [

{

test: /.css$/,

use: [

MiniCssExtractPlugin.loader,

"css-loader", // css-loader 負責解析 CSS 代碼, 處理 CSS 中的依賴

],

},

{

test: /\.js$/,

// 排除項 - 也是正則

exclude: /node_modules/,

// 使用的loader - 如果是配置項,則寫成對象

use: {

// 指定loader

loader: "babel-loader",

// 更好的在其他的浏覽器相容es6進階文法

options: {

// 預設方案和細節聲明 - 二維數組

presets: [

[

"@babel/preset-env",

{

// 隻打包使用的ES6新API的實作代碼

useBuiltIns: "usage",

// 指定core-js的版本号為2

corejs: { version: 2 },

},

],

],

},

},

},

],

},

plugins: [

// 編譯html的插件

new HTMLWebpackPlugin({

// 指定模闆存放的路徑

template: "./src/index.html",

// 在body中注入編譯好的檔案

inject: "body",

// 每一次編譯的bundle.js 帶一些哈希,防止緩存

hash: true,

// 關于html的壓縮處理

minify: {

// 移除屬性中的雙引号

removeAttributeQuotes: true,

// 移除注釋

removeComments: true,

// 去除換行和空格

collapseWhitespace: true,

},

}),

// 用 MiniCssExtractPlugin 抽離出 css 檔案,以 link 标簽的形式引入樣式檔案

new MiniCssExtractPlugin({

filename: "index.bundle-[hash].css", // 輸出的 css 檔案名為 index.css

}),

],

};

module.exports = options;

4.運作webpack

前端webpack術語|module、chunk、bundle的差別?

我們可以看出,index.css 和 common.js 在 index.js 中被引入,打包生成的 index.bundle-[hash].css 和 index.bundle-[hash].js 都屬于 chunk 0,utils.js 因為是獨立打包的,它生成的 utils.bundle-[hash].js 屬于 chunk 1。

前端webpack術語|module、chunk、bundle的差別?

一般來說一個 chunk 對應一個 bundle,比如上圖中的utils.js -> chunk 1 -> utils.bundle.js;但也有例外,比如說上圖中,我就用MiniCssExtractPlugin從 chunks 0 中抽離出了index.bundle.css檔案。

三、3種hash值詳解

1.webpack中的三種hash分别是:

  • hash:全局hash
  • chunkhash:分組hash
  • contenthash:内容hash

2.hash

webpack.config.js輸出檔案名規則修改為hash時。

output: {

// ./dist

path: path.resolve(__dirname, "dist"),

// 輸出 index.js 和 utils.js

filename: "./js/[name].bundle-[hash].js",

// 每次編譯的時候把上一次的内容給清空

clean: true,

},

plugins: [

// 用 MiniCssExtractPlugin 抽離出 css 檔案,以 link 标簽的形式引入樣式檔案

new MiniCssExtractPlugin({

filename: "index.bundle-[hash].css", // 輸出的 css 檔案名為 index.css

}),

],

預設的是hash,直接運作打包webpack,我們看看我們打包後的檔案是什麼樣的。

前端webpack術語|module、chunk、bundle的差別?

可以看到,所有檔案的檔案名hash值都是一緻的,那我們現在改一下index.css這個檔案。

body {

/* background-color: pink; */

background-color: blue;

}

運作打包webpack,我們看看我們打包後的檔案是什麼樣的。

前端webpack術語|module、chunk、bundle的差別?

可以看出,修改一個檔案,所有檔案的hash值跟着變。

結論:牽一發動全身,隻改了一個index.css,會導緻打包後所有檔案的hash值都改變。是以當打包名稱設定為hash時,整個項目檔案是一緻的,修改其中一個會導緻所有跟着一起改。

2.chunkhash

webpack.config.js輸出檔案名規則修改為chunkhash

output: {

// ./dist

path: path.resolve(__dirname, "dist"),

// 輸出 index.js 和 utils.js

filename: "./js/[name].bundle-[chunkhash].js",

// 每次編譯的時候把上一次的内容給清空

clean: true,

},

plugins: [

// 用 MiniCssExtractPlugin 抽離出 css 檔案,以 link 标簽的形式引入樣式檔案

new MiniCssExtractPlugin({

filename: "index.bundle-[chunkhash].css", // 輸出的 css 檔案名為 index.css

}),

],

預設的是chunkhash,直接運作打包webpack,我們看看我們打包後的檔案是什麼樣的。

前端webpack術語|module、chunk、bundle的差別?

我們可以看出,chunkhash值會根據入口檔案的不同而分出兩個陣營:

  • index.js、index.css一個陣營
  • utils.js一個陣營

那我們現在照樣修改一下index.css:

body {

/* background-color: pink; */

/* background-color: blue; */

background-color: yellow;

}

重新運作webpack打包看看:

前端webpack術語|module、chunk、bundle的差別?

可以看出,index.css修改後會影響index.css、index.js的chunkhash值。

結論:當規則為chunkhash時,打包後的chunkhash值會根據入口檔案的不同而不一樣,當某個入口檔案修改後重新打包,會導緻本入口檔案關聯的所有檔案的chunkhash值都修改,但是不會影響到其他入口檔案的chunkhash值。

3.contenthash

webpack.config.js輸出檔案名規則修改為contenthash

output: {

// ./dist

path: path.resolve(__dirname, "dist"),

// 輸出 index.js 和 utils.js

filename: "./js/[name].bundle-[contenthash].js",

// 每次編譯的時候把上一次的内容給清空

clean: true,

},

plugins: [

// 用 MiniCssExtractPlugin 抽離出 css 檔案,以 link 标簽的形式引入樣式檔案

new MiniCssExtractPlugin({

filename: "index.bundle-[contenthash].css", // 輸出的 css 檔案名為 index.css

}),

],

預設的是contenthash,直接運作打包webpack,我們看看我們打包後的檔案是什麼樣的。

前端webpack術語|module、chunk、bundle的差別?

可以看到,每個檔案的contenthash值都不一樣,每個檔案的contenthash值都是根據自身的内容去生成的,那我們現在修改一下index.css:

body {

/* background-color: pink; */

/* background-color: blue; */

/* background-color: yellow; */

background-color: red;

}

重新運作webpack打包看看:

前端webpack術語|module、chunk、bundle的差別?

可以看出,index.css修改後隻會影響index.css的contenthash值,也就是自己的contenthash值。

結論:當規則為contenthash時,每個檔案的contenthash值都是根據自身内容而生成,當某個檔案内容修改時,打包後隻會修改其本身的contenthash值,不會影響其他檔案的contenthash值。

總結

同一份邏輯代碼中module,chunk 和 bundle 就是在不同轉換場景下的三個術語,我們直接寫出來的是 module,webpack 處理時是 chunk,最後生成浏覽器可以直接運作的 bundle。

當打包名稱設定為hash時,整個項目檔案是一緻的,修改其中一個會導緻所有跟着一起改。當規則為chunkhash時,打包後的chunkhash值會根據入口檔案的不同而不一樣,當某個入口檔案修改後重新打包,會導緻本入口檔案關聯的所有檔案的chunkhash值都修改,但是不會影響到其他入口檔案的chunkhash值。當規則為contenthash時,每個檔案的contenthash值都是根據自身内容而生成,當某個檔案内容修改時,打包後隻會修改其本身的contenthash值,不會影響其他檔案的contenthash值。

繼續閱讀