本节描述了 webpack 内部机制,对插件开发者可能会有用。
捆绑是一个函数,它接收一些文件并输出其他文件。
但在输入和输出之间,它还有 模块、入口点、块、块组以及许多其他中间部分。
项目中使用的每个文件都是一个 模块
./index.js
import app from './app.js';
./app.js
export default 'the app';
通过相互使用,模块形成了一个图 (ModuleGraph
)。
在捆绑过程中,模块被组合成块。块组合成块组,并通过模块形成一个图 (ChunkGraph
)。当你描述一个入口点时,在幕后,你创建了一个包含一个块的块组。
./webpack.config.js
module.exports = {
entry: './index.js',
};
创建了一个名为 main
的块组 (main
是入口点的默认名称)。这个块组包含 ./index.js
模块。当解析器处理 ./index.js
中的导入时,新的模块将被添加到这个块中。
另一个例子
./webpack.config.js
module.exports = {
entry: {
home: './home.js',
about: './about.js',
},
};
创建了两个名为 home
和 about
的块组。它们各自包含一个模块块 - home
包含 ./home.js
,about
包含 ./about.js
。
一个块组中可能包含多个块。例如,SplitChunksPlugin 会将一个块拆分成一个或多个块。
块有两种形式
initial
是入口点的主要块。这个块包含你为入口点指定的所有模块及其依赖项。non-initial
是一个可能被延迟加载的块。当使用 动态导入 或 SplitChunksPlugin 时,它可能会出现。每个块都有一个对应的资源。资源是输出文件 - 捆绑的结果。
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);
});
创建名为main
的初始块。它包含
./src/index.jsx
react
react-dom
以及它们的所有依赖项,除了./app.jsx
为./app.jsx
创建非初始块,因为此模块是动态导入的。
输出
/dist/main.js
- 一个initial
块/dist/394.js
- non-initial
块默认情况下,non-initial
块没有名称,因此使用唯一 ID 而不是名称。使用动态导入时,我们可以使用"魔法"注释显式指定块名称
import(
/* webpackChunkName: "app" */
'./app.jsx'
).then((App) => {
ReactDOM.render(<App />, root);
});
输出
/dist/main.js
- 一个initial
块/dist/app.js
- non-initial
块输出文件名的名称受配置中的两个字段影响
output.filename
- 用于initial
块文件output.chunkFilename
- 用于non-initial
块文件initial
和non-initial
。在这些情况下,使用output.filename
。这些字段中可以使用一些占位符。最常见的是
[id]
- 块 ID(例如 [id].js
-> 485.js
)[name]
- 块名称(例如 [name].js
-> app.js
)。如果块没有名称,则将使用其 ID[contenthash]
- 输出文件内容的 md4 哈希(例如 [contenthash].js
-> 4ea6ff1de66c537eb9b2.js
)