幕后

本节描述了 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',
  },
};

创建了两个名为 homeabout 的块组。它们各自包含一个模块块 - home 包含 ./home.jsabout 包含 ./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块文件
  • 在某些情况下,块被用作initialnon-initial。在这些情况下,使用output.filename

这些字段中可以使用一些占位符。最常见的是

  • [id] - 块 ID(例如 [id].js -> 485.js
  • [name] - 块名称(例如 [name].js -> app.js)。如果块没有名称,则将使用其 ID
  • [contenthash] - 输出文件内容的 md4 哈希(例如 [contenthash].js -> 4ea6ff1de66c537eb9b2.js

4 位贡献者

smelukovEugeneHlushkochenxsanamirsaeed671