在 Compilation 阶段,模块会被加载 (loaded)、封存 (sealed)、优化 (optimized)、分块 (chunked)、哈希 (hashed) 和重新创建 (restored),Compilation 对象包含了当前的模块资源、编译生成资源、变化的文件等。当 Webpack 以监听(watch)模式运行时,每当检测到一个文件变化,一次新的 Compilation 将被创建。Compilation 对象也提供了很多事件回调供插件做扩展,通过 Compilation 也能读取到 Compiler 对象。

Compilation 钩子

在 Compilation 中处理的对象分别是modulechunkasset,由 modules 组成chunks,由chunks生成assets,处理顺序是:module → modules → chunks → assets,先从单个 module 开始处理,查找依赖关系,最后完成单个 module 处理,完成全部modules 之后,开始 chunks 阶段处理,最后在根据优化配置,按需生成 assets。整个 Compilation 的生命周期钩子虽然比较多,但是大规律上是围绕这个顺序进行的。

带 ★ 的是比较重要的钩子。

image.png

Compilation 和 Stats 对象

在 Webpack 的回调函数中会得到 stats 对象。这个对象实际来自于 Compilation.getStats(),返回的是主要含有 moduleschunksassets 三个属性值的对象。

  • modules:记录了所有解析后的模块
  • chunks:记录了所有 chunk
  • assets:记录了所有要生成的文件

Stats 对象本质上来自于 lib/Stats.js 的类实例,常用的方法 stats.hasWarnings()stats.hasErrors()stats.toJson()stats.toString() 都可以在这个类里面找到对应的实现。

Stats 对象数据结构

Stats 对象的 JSON 数据结构,除了通过 Compilation.getStats() 获得,还可以在 webpack 回调中,通过 callback 参数获得:

  1. webpack(config, (err, stats) => {
  2. console.log(stats.toJson())
  3. })

还可以通过 webpack-cli 的选项将本次打包的 stats 存入一个 json 文件:webpack --profile --json > compilation-stats.json

stats.toJson() 得到的数据结构格式如下:

  1. {
  2. 'version': '5.0.0-alpha.6', // 用来编译的 webpack 的版本
  3. 'hash': '11593e3b3ac85436984a', // 编译使用的 hash
  4. 'time': 2469, // 编译耗时 (ms)
  5. 'filteredModules': 0, // 当 `exclude`传入`toJson` 函数时,统计被无视的模块的数量
  6. 'outputPath': '/', // path to webpack 输出目录的 path 路径
  7. 'assetsByChunkName': {
  8. // 用作映射的 chunk 的名称
  9. 'main': [
  10. 'web.js?h=11593e3b3ac85436984a'
  11. ],
  12. 'named-chunk': [
  13. 'named-chunk.web.js'
  14. ],
  15. 'other-chunk': [
  16. 'other-chunk.js',
  17. 'other-chunk.css'
  18. ],
  19. },
  20. 'assets': [
  21. // asset 对象 (asset objects) 的数组
  22. ],
  23. 'chunks': [
  24. // chunk 对象 (chunk objects) 的数组
  25. ],
  26. 'modules': [
  27. // 模块对象 (module objects) 的数组
  28. ],
  29. 'errors': [
  30. // 错误字符串 (error string) 的数组
  31. ],
  32. 'warnings': [
  33. // 警告字符串 (warning string) 的数组
  34. ],
  35. }

这里面除了编译基本信息、报错和 warnings 之外,就是moduleschunksassets 三个对应的数组,里面是单个的 modulechunkasset

Tips:stats.toJson 可以指定要不要输出对应的数据。例如不想输出 moduleschunks,可以使用 stats.toJson(modules: false, chunks: false)

module

在每个 module 中,我们可以得到它的所有信息,这些信息可以分为四大类:

  1. 基本信息:包括最基本的内容、大小、id;
  2. 依赖关系:module.reasons 对象描述了这个模块被加入依赖图表的理由,包含了引入的方式、引入的 module 信息及其对应代码在第几行第几列等,可以通过这个计算出 module 之间的依赖关系图表(graph);
  3. chunks 和 assets 关系:module.chunksmodule.assets 包含到 chunks 和 assets 中的对应 id 等;
  4. 被 webpack 处理的后的信息:包含 module.failedmodule.errorsmodule.warnings 等。
  1. {
  2. 'assets': [
  3. // asset 对象 (asset objects) 的数组
  4. ],
  5. 'built': true, // 表示这个模块会参与 Loaders , 解析,并被编译
  6. 'cacheable': true, // 表示这个模块是否会被缓存
  7. 'chunks': [
  8. // 包含这个模块的 chunks 的 id
  9. ],
  10. 'errors': 0, // 处理这个模块发现的错误的数量
  11. 'failed': false, // 编译是否失败
  12. 'id': 0, // 这个模块的 ID (类似于 `module.id`)
  13. 'identifier': '(webpack)\\\\test\\\\browsertest\\\\lib\\\\index.web.js', // webpack 内部使用的唯一的标识
  14. 'name': './lib/index.web.js', // 实际文件的地址
  15. 'optional': false, // 每一个对这个模块的请求都会包裹在 `try... catch` 内 (与 ESM 无关)
  16. 'prefetched': false, // 表示这个模块是否会被 prefetched
  17. 'profile': {
  18. // 有关 `--profile` flag 的这个模块特有的编译数据 (ms)
  19. 'building': 73, // 载入和解析
  20. 'dependencies': 242, // 编译依赖
  21. 'factory': 11, // 解决依赖
  22. },
  23. 'reasons': [
  24. // 见下文描述
  25. ],
  26. 'size': 3593, // 预估模块的大小 (byte)
  27. 'source': '// Should not break it...\\r\\nif(typeof...', // 字符串化的输入
  28. 'warnings': 0, // 处理模块时警告的数量
  29. }

其中 module.reasons 数据结构如下:

  1. {
  2. 'loc': '33:24-93', // 导致这个被加入依赖图标的代码行数
  3. 'module': './lib/index.web.js', // 所基于模块的相对地址 context
  4. 'moduleId': 0, // 模块的 ID
  5. 'moduleIdentifier': '(webpack)\\\\test\\\\browsertest\\\\lib\\\\index.web.js', // 模块的地址
  6. 'moduleName': './lib/index.web.js', // 可读性更好的模块名称 (用于 "更好的打印 (pretty-printing)")
  7. 'type': 'require.context', // 使用的请求的种类 (type of request)
  8. 'userRequest': '../../cases', // 用来 `import` 或者 `require` 的源字符串
  9. }

chunk

在每个 chunk 中,信息也可以分为四大类:

  1. 基本信息:包括最基本的内容、大小、id;
  2. 来源:chunk.origins 对象描述了这个模块被加入的理由,包含了引入的方式、引入的 module 信息及其对应代码在第几行第几列等,可以通过这个计算出 module 之间的依赖关系图表(graph);
  3. 引用关系:chunk.parentschunk.children 被引用和引用的 ids;
  4. 包含和被包含:chunk.fileschunk.modules 包含到 assets 和自己包含 modules 中信息等。
  1. {
  2. 'entry': true, // 表示这个 chunk 是否包含 webpack 的运行时
  3. 'files': [
  4. // 一个包含这个 chunk 的文件名的数组
  5. ],
  6. 'filteredModules': 0, // 见上文的 结构
  7. 'id': 0, // 这个 chunk 的 id
  8. 'initial': true, // 表示这个 chunk 是开始就要加载还是 懒加载 (lazy-loading)
  9. 'modules': [
  10. // 模块对象 (module objects) 的数组
  11. 'web.js?h=11593e3b3ac85436984a',
  12. ],
  13. 'names': [
  14. // 包含在这个 chunk 内的 chunk 的名字的数组
  15. ],
  16. 'origins': [
  17. // 下文详述
  18. ],
  19. 'parents': [], // 父 chunk 的 ids
  20. // 生成 assets 的原因
  21. 'reason': 'split chunk (cache group: asyncVendors) (name: async)',
  22. 'hash': '170746935298270ad813',
  23. // 自己引用谁
  24. 'children': [],
  25. // 引用的顺序
  26. 'childrenByOrder': {},
  27. 'modules': [],
  28. 'rendered': true, // 表示这个 chunk 是否会参与进编译
  29. 'size': 188057, // chunk 的大小 (byte)
  30. }

chunk.origins 对应的格式如下:

  1. {
  2. 'loc': '', // 具体是哪行生成了这个 chunk
  3. 'module': '(webpack)\\\\test\\\\browsertest\\\\lib\\\\index.web.js', // 模块的位置
  4. 'moduleId': 0, // 模块的 ID
  5. 'moduleIdentifier': '(webpack)\\\\test\\\\browsertest\\\\lib\\\\index.web.js', // 模块的地址
  6. 'moduleName': './lib/index.web.js', // 模块的相对地址
  7. 'name': 'main', // chunk 的名称
  8. 'reasons': [
  9. // 模块对象中`reason`的数组
  10. ],
  11. }

asset

asset 相对简单一些,内容如下: