本节描述了 webpack 的内部机制,对插件开发者很有用。
打包是一个函数,它接收一些文件并输出另一些文件。
但在输入和输出之间,它还有模块(modules)、入口点(entry points)、代码块(chunks)、代码块组(chunk groups)以及许多其他中间部分。
项目中使用的每个文件都是一个模块(Module)
./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
是一个可能被延迟加载的代码块。它在使用动态导入(dynamic import)或SplitChunksPlugin时可能会出现。每个代码块都有一个对应的资源(asset)。资源就是输出文件 —— 打包的结果。
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
的 initial 代码块。它包含
./src/index.jsx
react
react-dom
及其所有依赖,除了 ./app.jsx
。
由于 ./app.jsx
模块是动态导入的,因此为其创建了 non-initial 代码块。
输出
/dist/main.js
- 一个 initial
代码块/dist/394.js
- non-initial
代码块默认情况下,non-initial 代码块没有名称,因此会使用唯一 ID 而不是名称。在使用动态导入时,我们可以通过使用“魔法注释”("magic" comment)来显式指定代码块名称
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
代码块文件output.filename
。这些字段中可以使用一些占位符。最常用的是
[id]
- 代码块 ID(例如 [id].js
-> 485.js
)[name]
- 代码块名称(例如 [name].js
-> app.js
)。如果代码块没有名称,则会使用其 ID。[contenthash]
- 输出文件内容的 md4 哈希值(例如 [contenthash].js
-> 4ea6ff1de66c537eb9b2.js
)