揭示 Webpack 內(nèi)部原理

2023-05-15 17:26 更新
此章節(jié)描述 webpack 內(nèi)部實(shí)現(xiàn),對于插件開發(fā)人員可能會提供幫助

打包,是指處理某些文件并將其輸出為其他文件的能力。

但是,在輸入和輸出之間,還包括有 模塊, 入口起點(diǎn), chunk, chunk 組和許多其他中間部分。

主要部分

項(xiàng)目中使用的每個文件都是一個 模塊

./index.js

import app from './app.js';

./app.js

export default 'the app';

通過互相引用,這些模塊會形成一個圖(?ModuleGraph?)數(shù)據(jù)結(jié)構(gòu)。

在打包過程中,模塊會被合并成 chunk。 chunk 合并成 chunk 組,并形成一個通過模塊互相連接的圖(?ModuleGraph?)。 那么如何通過以上來描述一個入口起點(diǎn):在其內(nèi)部,會創(chuàng)建一個只有一個 chunk 的 chunk 組。

./webpack.config.js

module.exports = {
  entry: './index.js',
};

這會創(chuàng)建出一個名為 main 的 chunk 組(main 是入口起點(diǎn)的默認(rèn)名稱)。 此 chunk 組包含 ./index.js 模塊。隨著 parser 處理 ./index.js 內(nèi)部的 import 時, 新模塊就會被添加到此 chunk 中。

另外的一個示例:

./webpack.config.js

module.exports = {
  entry: {
    home: './home.js',
    about: './about.js',
  },
};

這會創(chuàng)建出兩個名為 ?home? 和 ?about? 的 chunk 組。 每個 chunk 組都有一個包含一個模塊的 chunk:?./home.js? 對應(yīng) ?home?,?./about.js? 對應(yīng) ?about?

一個 chunk 組中可能有多個 chunk。例如,SplitChunksPlugin 會將一個 chunk 拆分為一個或多個 chunk。

chunk

chunk 有兩種形式:

  • ?initial(初始化)? 是入口起點(diǎn)的 main chunk。此 chunk 包含為入口起點(diǎn)指定的所有模塊及其依賴項(xiàng)。
  • ?non-initial? 是可以延遲加載的塊??赡軙霈F(xiàn)在使用 動態(tài)導(dǎo)入(dynamic imports) 或者 SplitChunksPlugin 時。

每個 chunk 都有對應(yīng)的 asset(資源)。資源,是指輸出文件(即打包結(jié)果)。

webpack.config.js

module.exports = {
  entry: './src/index.jsx',
};

./src/index.jsx

import React from 'react';
import ReactDOM from 'react-dom';

import('./app.jsx').then((App) => {
  ReactDOM.render(<App />, root);
});

這會創(chuàng)建出一個名為 ?main? 的 initial chunk。其中包含:

  • ?./src/index.jsx?
  • ?react?
  • ?react-dom?

以及除 ?./app.jsx? 外的所有依賴

然后會為 ?./app.jsx? 創(chuàng)建 non-initial chunk,這是因?yàn)?nbsp;?./app.jsx? 是動態(tài)導(dǎo)入的。

Output:

  • ?/dist/main.js? - 一個 ?initial? chunk
  • ?/dist/394.js? - ?non-initial? chunk

默認(rèn)情況下,這些 ?non-initial? chunk 沒有名稱,因此會使用唯一 ID 來替代名稱。 在使用動態(tài)導(dǎo)入時,我們可以通過使用 magic comment(魔術(shù)注釋) 來顯式指定 chunk 名稱:

import(
  /* webpackChunkName: "app" */
  './app.jsx'
).then((App) => {
  ReactDOM.render(<App />, root);
});

Output:

  • ?/dist/main.js? - 一個 ?initial? chunk
  • ?/dist/app.js? - ?non-initial? chunk

output(輸出)

輸出文件的名稱會受配置中的兩個字段的影響:

  • ?output.filename? - 用于 ?initial? chunk 文件
  • ?output.chunkFilename? - 用于 ?non-initial? chunk 文件
  • 在某些情況下,使用 ?initial? 和 ?non-initial? 的 chunk 時,可以使用 ?output.filename?。

這些字段中會有一些 占位符。常用的占位符如下:

  • ?[id]? - chunk id(例如 ?[id].js? -> ?485.js?)
  • ?[name]? - chunk name(例如 ?[name].js? -> ?app.js?)。如果 chunk 沒有名稱,則會使用其 id 作為名稱
  • ?[contenthash]? - 輸出文件內(nèi)容的 md4-hash(例如 ?[contenthash].js? -> ?4ea6ff1de66c537eb9b2.js?)


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號