在 Compilation 阶段,模块会被加载 (loaded)、封存 (sealed)、优化 (optimized)、分块 (chunked)、哈希 (hashed) 和重新创建 (restored),Compilation 对象包含了当前的模块资源、编译生成资源、变化的文件等。当 Webpack 以监听(watch)模式运行时,每当检测到一个文件变化,一次新的 Compilation 将被创建。Compilation 对象也提供了很多事件回调供插件做扩展,通过 Compilation 也能读取到 Compiler 对象。
Compilation 钩子
在 Compilation 中处理的对象分别是module、chunk、asset,由 modules 组成chunks,由chunks生成assets,处理顺序是:module → modules → chunks → assets,先从单个 module 开始处理,查找依赖关系,最后完成单个 module 处理,完成全部modules 之后,开始 chunks 阶段处理,最后在根据优化配置,按需生成 assets。整个 Compilation 的生命周期钩子虽然比较多,但是大规律上是围绕这个顺序进行的。
带 ★ 的是比较重要的钩子。

Compilation 和 Stats 对象
在 Webpack 的回调函数中会得到 stats 对象。这个对象实际来自于 Compilation.getStats(),返回的是主要含有 modules、chunks 和 assets 三个属性值的对象。
- modules:记录了所有解析后的模块
 - chunks:记录了所有 chunk
 - assets:记录了所有要生成的文件
 
Stats 对象本质上来自于 lib/Stats.js 的类实例,常用的方法 stats.hasWarnings()、stats.hasErrors()、stats.toJson() 和 stats.toString() 都可以在这个类里面找到对应的实现。
Stats 对象数据结构
Stats 对象的 JSON 数据结构,除了通过 Compilation.getStats() 获得,还可以在 webpack 回调中,通过 callback 参数获得:
webpack(config, (err, stats) => {console.log(stats.toJson())})
还可以通过 webpack-cli 的选项将本次打包的 stats 存入一个 json 文件:webpack --profile --json > compilation-stats.json 。
stats.toJson() 得到的数据结构格式如下:
{'version': '5.0.0-alpha.6', // 用来编译的 webpack 的版本'hash': '11593e3b3ac85436984a', // 编译使用的 hash'time': 2469, // 编译耗时 (ms)'filteredModules': 0, // 当 `exclude`传入`toJson` 函数时,统计被无视的模块的数量'outputPath': '/', // path to webpack 输出目录的 path 路径'assetsByChunkName': {// 用作映射的 chunk 的名称'main': ['web.js?h=11593e3b3ac85436984a'],'named-chunk': ['named-chunk.web.js'],'other-chunk': ['other-chunk.js','other-chunk.css'],},'assets': [// asset 对象 (asset objects) 的数组],'chunks': [// chunk 对象 (chunk objects) 的数组],'modules': [// 模块对象 (module objects) 的数组],'errors': [// 错误字符串 (error string) 的数组],'warnings': [// 警告字符串 (warning string) 的数组],}
这里面除了编译基本信息、报错和 warnings 之外,就是modules、chunks 和 assets 三个对应的数组,里面是单个的 module、chunk 和 asset。
Tips:stats.toJson 可以指定要不要输出对应的数据。例如不想输出 modules 和 chunks,可以使用 stats.toJson(modules: false, chunks: false)。
module
在每个 module 中,我们可以得到它的所有信息,这些信息可以分为四大类:
- 基本信息:包括最基本的内容、大小、id;
 - 依赖关系:
module.reasons对象描述了这个模块被加入依赖图表的理由,包含了引入的方式、引入的 module 信息及其对应代码在第几行第几列等,可以通过这个计算出 module 之间的依赖关系图表(graph); - chunks 和 assets 关系:
module.chunks和module.assets包含到 chunks 和 assets 中的对应 id 等; - 被 webpack 处理的后的信息:包含 
module.failed、module.errors、module.warnings等。 
{'assets': [// asset 对象 (asset objects) 的数组],'built': true, // 表示这个模块会参与 Loaders , 解析,并被编译'cacheable': true, // 表示这个模块是否会被缓存'chunks': [// 包含这个模块的 chunks 的 id],'errors': 0, // 处理这个模块发现的错误的数量'failed': false, // 编译是否失败'id': 0, // 这个模块的 ID (类似于 `module.id`)'identifier': '(webpack)\\\\test\\\\browsertest\\\\lib\\\\index.web.js', // webpack 内部使用的唯一的标识'name': './lib/index.web.js', // 实际文件的地址'optional': false, // 每一个对这个模块的请求都会包裹在 `try... catch` 内 (与 ESM 无关)'prefetched': false, // 表示这个模块是否会被 prefetched'profile': {// 有关 `--profile` flag 的这个模块特有的编译数据 (ms)'building': 73, // 载入和解析'dependencies': 242, // 编译依赖'factory': 11, // 解决依赖},'reasons': [// 见下文描述],'size': 3593, // 预估模块的大小 (byte)'source': '// Should not break it...\\r\\nif(typeof...', // 字符串化的输入'warnings': 0, // 处理模块时警告的数量}
其中 module.reasons 数据结构如下:
{'loc': '33:24-93', // 导致这个被加入依赖图标的代码行数'module': './lib/index.web.js', // 所基于模块的相对地址 context'moduleId': 0, // 模块的 ID'moduleIdentifier': '(webpack)\\\\test\\\\browsertest\\\\lib\\\\index.web.js', // 模块的地址'moduleName': './lib/index.web.js', // 可读性更好的模块名称 (用于 "更好的打印 (pretty-printing)")'type': 'require.context', // 使用的请求的种类 (type of request)'userRequest': '../../cases', // 用来 `import` 或者 `require` 的源字符串}
chunk
在每个 chunk 中,信息也可以分为四大类:
- 基本信息:包括最基本的内容、大小、id;
 - 来源:
chunk.origins对象描述了这个模块被加入的理由,包含了引入的方式、引入的 module 信息及其对应代码在第几行第几列等,可以通过这个计算出 module 之间的依赖关系图表(graph); - 引用关系:
chunk.parents和chunk.children被引用和引用的 ids; - 包含和被包含:
chunk.files和chunk.modules包含到 assets 和自己包含 modules 中信息等。 
{'entry': true, // 表示这个 chunk 是否包含 webpack 的运行时'files': [// 一个包含这个 chunk 的文件名的数组],'filteredModules': 0, // 见上文的 结构'id': 0, // 这个 chunk 的 id'initial': true, // 表示这个 chunk 是开始就要加载还是 懒加载 (lazy-loading)'modules': [// 模块对象 (module objects) 的数组'web.js?h=11593e3b3ac85436984a',],'names': [// 包含在这个 chunk 内的 chunk 的名字的数组],'origins': [// 下文详述],'parents': [], // 父 chunk 的 ids// 生成 assets 的原因'reason': 'split chunk (cache group: asyncVendors) (name: async)','hash': '170746935298270ad813',// 自己引用谁'children': [],// 引用的顺序'childrenByOrder': {},'modules': [],'rendered': true, // 表示这个 chunk 是否会参与进编译'size': 188057, // chunk 的大小 (byte)}
chunk.origins 对应的格式如下:
{'loc': '', // 具体是哪行生成了这个 chunk'module': '(webpack)\\\\test\\\\browsertest\\\\lib\\\\index.web.js', // 模块的位置'moduleId': 0, // 模块的 ID'moduleIdentifier': '(webpack)\\\\test\\\\browsertest\\\\lib\\\\index.web.js', // 模块的地址'moduleName': './lib/index.web.js', // 模块的相对地址'name': 'main', // chunk 的名称'reasons': [// 模块对象中`reason`的数组],}
asset
asset 相对简单一些,内容如下:
