webpack stats 详解:通过stats: "detailed"预设输出深度编译报告
【免费下载链接】webpackA bundler for javascript and friends. Packs many modules into a few bundled assets. Code Splitting allows for loading parts of the application on demand. Through "loaders", modules can be CommonJs, AMD, ES6 modules, CSS, Images, JSON, Coffeescript, LESS, ... and your custom stuff.项目地址: https://gitcode.com/GitHub_Trending/web/webpack
在 webpack 中,stats选项负责控制构建完成后打印到终端(或通过Stats对象导出)的统计信息格式与详细程度。本仓库webpack(JavaScript 及其生态的模块打包器)在 examples/stats-detailed 中提供了一个最精简的示例:仅一行console.log("Hello World!")的入口文件,配合stats: "detailed"配置,用于演示"详细模式"下 stats 报告的输出形态。读完本文,你将理解detailed预设由哪些选项构成、它的输出每一段分别代表什么含义、与normal/verbose等预设的差异,以及如何在配置、命令行与 JavaScript API 三个层面按需定制 stats 输出。
示例总览:最小项目与它的完整编译信息
该示例共有两个源文件加一份由构建自动产出的产物:
- 入口模块 examples/stats-detailed/example.js:内容只有一行
console.log("Hello World!");,代表一个"带副作用(side effects)但无导出(no exports)"的最简单模块。 - 配置文件 examples/stats-detailed/webpack.config.js:指定产物输出到
dist/output.js,并把stats设为字符串预设"detailed"。
"use strict"; const path = require("path"); /** @type {import("webpack").Configuration} */ const config = { output: { path: path.join(__dirname, "dist"), filename: "output.js" }, stats: "detailed" }; module.exports = config;构建产物 examples/stats-detailed/README.md 中展示的dist/output.js是一个 28 字节的精简 bundle:外层是 webpack 自带的webpackBootstrapIIFE,模块注释!*** ./example.js ***!标明了模块路径,其下方标注/*! unknown exports (runtime-defined) */(该模块是 CommonJS 风格、导出由运行时决定)与/*! runtime requirements: */(该模块自身无额外运行时要求),随后是压缩后的业务代码本身。
这个示例说明:即便构建逻辑简单到极致,detailed预设也会在终端打印出一份分层的、带有"模块级诊断"与"插件内部日志"的深度报告。理解这份报告正是掌握 webpack 编译全流程的捷径。
detailed预设的组成:从源码看它打开了哪些开关
字符串形式的stats值在 webpack 内部被称为"预设(preset)"。源码 lib/stats/DefaultStatsPresetPlugin.js 中的NAMED_PRESETS对象集中定义了全部预设:verbose、detailed、minimal、errors-only、errors-warnings、summary、none,加上默认的normal。
其中detailed预设(lib/stats/DefaultStatsPresetPlugin.js)等价于一次性开启下列选项:
| 选项 | detailed 取值 | 作用 |
|---|---|---|
hash | true | 显示本次编译的哈希 |
builtAt | true | 显示构建完成时间戳 |
relatedAssets | true | 显示与资产相关的额外资产(如 source map) |
entrypoints | true | 显示每个入口点的资产构成 |
chunkGroups | true | 显示 chunk group 结构 |
ids | true | 显示模块 / chunk 的数值 id |
chunks | true | 逐 chunk 列出 |
chunkRelations | true | 显示 chunk 之间的父子引用关系 |
chunkOrigins | true | 显示每个 chunk 的创建来源 |
depth | true | 显示模块在依赖图中的深度 |
usedExports/providedExports | true | 显示模块被使用 / 提供的导出 |
optimizationBailout | true | 显示为何未能进行优化(如 scope hoisting 失败原因) |
errorDetails/errorCause/errorErrors | true | 展开错误详情、错误原因与错误栈 |
publicPath | true | 显示 publicPath(本示例中为相对产物路径dist/) |
logging | true | 输出插件内部日志(详见下文 LOG 段) |
runtimeModules | true | 把运行时模块计入模块列表 |
errorsSpace/warningsSpace/modulesSpace/assetsSpace/reasonsSpace | 1000 | 各类条目最多显示 1000 条(相较默认 15 条的折叠窗口极大放宽) |
exclude | false | 不排除任何模块 |
正是因为这些开关被整体拉高,detailed报告比默认的normal长得多,常用于排障、性能分析与理解模块图。
从配置到报告:stats 的解析与渲染链路
在源码层面,字符串预设真正生效的路径如下:
- 用户在配置中写
stats: "detailed"。 - 编译期,
createStatsOptions(lib/Compilation.js)把字符串/布尔值包装成{ preset: "detailed" }这样的对象:字符串会被归一化为{ preset: <字符串> },布尔值false/true分别映射为preset: "none"/preset: "normal"。 - 若存在
preset,触发compilation.hooks.statsPreset.for(preset)钩子;DefaultStatsPresetPlugin.js 正是通过 tap 这个钩子,把NAMED_PRESETS.detailed里的每一项applyDefaults写入待归一化选项。 - 随后
statsNormalize钩子把剩余未指定的选项用DEFAULTS(lib/stats/DefaultStatsPresetPlugin.js)补齐,完成归一化。 - 打印阶段,
Stats.toString(lib/Stats.js)使用StatsFactory把 Compilation 抽取为结构化数据,再用StatsPrinter格式化为终端文本——注意toString传入forToString: true,因此许多auto类默认项(如errorDetails)会按"面向终端展示"的方式展开;若用stats.toJson()导出机器可读 JSON,则走forToString: false的另一套逻辑。
可以推断,这份detailed预设本质上是"在normal之上覆盖了一批高信息量开关",而非从零构建的全新配置,因为每个预设都只声明自己需要覆盖的字段,其余字段全部回落到DEFAULTS。
逐段解读示例中的详细输出
examples/stats-detailed/README.md 中# Info → Production mode一节展示了完整运行输出,下面逐段说明。
全局资产与入口点行
PublicPath: dist/ asset output.js 28 bytes {792} [emitted] [minimized] (name: main) Entrypoint main 28 bytes = output.jsPublicPath: dist/:由publicPath: true打印,此处是输出目录相对路径。asset output.js ... {792}:{792}是资产所属 chunk 的 id;[emitted]表示该资产是新产出(未被缓存复用);[minimized]表示经过压缩(production 模式的默认行为)。Entrypoint main 28 bytes = output.js:入口点main的最终产物构成。
chunk 与模块明细行
chunk {792} (runtime: main) output.js (main) 29 bytes [entry] [rendered] > ./example.js main ./example.js [695] 29 bytes {792} [depth 0] [built] [code generated] [no exports used] Statement (ExpressionStatement) with side effects in source code at 1:0-28 ModuleConcatenation bailout: Module is not in strict modechunk {792} ... [entry] [rendered]:id 为 792 的入口 chunk,归属于 runtimemain;[rendered]指已完成代码生成阶段。> ./example.js main:chunkOrigins开启后显示的 chunk 来源——由模块./example.js的main入口创建。./example.js [695] 29 bytes {792} [depth 0] [built] [code generated]:模块路径、数值 id、大小、所属 chunk、[depth 0](位于依赖图根层)、[built](已完成构建)、[code generated](已完成代码生成)。示例中的"29 bytes"与产物 28 bytes 的差异来自模块注释等描述信息不计入产物。[no exports used]:usedExports结果显示没有使用任何导出(模块确实也无导出)。Statement (ExpressionStatement) with side effects in source code at 1:0-28:这是optimizationBailout(结合 side-effects 分析)的输出,指出第 1 行 0-28 列存在带副作用的表达式语句,因此该语句不可被 tree shaking 删除。ModuleConcatenation bailout: Module is not in strict mode:scope hoisting(模块拼接优化)在此模块上失败的明确原因——模块不在严格模式下。这正是optimizationBailout: true的价值:它把"为什么没被优化"直接打印出来。
插件内部日志段
输出末尾是若干LOG from webpack.xxx分组,这是logging: true(normal下默认仅info级且多隐藏)打开的结果:
LOG from webpack.Compilation 1 modules hashed, 0 from cache (1 variants per module in average) 100% code generated (1 generated, 0 from cache) + 24 hidden lines LOG from webpack.FlagDependencyExportsPlugin 0% of exports of modules have been determined (...) LOG from webpack.buildChunkGraph 2 queue items processed (1 blocks) 0 chunk groups connected ... LOG from webpack.FileSystemInfo 1 new snapshots created File info in cache: 1 timestamps 1 hashes 1 timestamp hash combinations ...webpack.Compilation:哈希(hashed)、代码生成(code generated)等核心阶段的统计。webpack.FlagDependencyExportsPlugin:依赖导出标记插件的进展(本示例仅 1 个无声明导出模块,因此完成度 0% 属正常)。webpack.buildChunkGraph:chunk 图构建过程(queue 处理、chunk group 合并等)。webpack.FileSystemInfo:文件系统快照与缓存命中情况——这是 webpack 持久化缓存(文件系统缓存)是否生效的直接观察窗口。+ N hidden lines:每组日志默认只展示摘要行,其余折叠。若想看到全部日志,可配合infrastructureLogging.level或进一步放宽日志级别。
末行webpack X.X.X compiled successfully (...)即hash+builtAt两选项渲染出的完成摘要。
命令行与 JavaScript API:三种启用方式
stats不止能写在配置里,还存在两种等价入口:
- 配置文件:如本示例,在 webpack.config.js 中写
stats: "detailed"(也支持对象形式,例如stats: { chunks: true, reasons: true })。 - 命令行(CLI):使用
--stats detailed或针对单个开关的旗标(如--stats-error-details、--stats-chunks)临时覆盖配置;这类旗标的具体错误详情提示可参考 lib/stats/DefaultStatsPrinterPlugin.js 中对stats.errorDetails的说明。 - JavaScript API:当通过编程方式使用 webpack 时,拿到
stats对象后调用stats.toString("detailed")可得到与终端一致的文本,调用stats.toJson("detailed")可得到对应的结构化 JSON,二者皆会走上述createStatsOptions的归一化流程(lib/Stats.js)。
另外需要说明:所有预设均可与对象形式混用,例如stats: { preset: "detailed", excludeModules: [/node_modules/] },预设铺底、再按需覆盖。同样的预设体系还支撑了仓库内 examples/stats-minimal、examples/stats-normal、examples/stats-summary、examples/stats-none 等系列示例,它们与本示例共用同一份example.js,只替换stats取值,即可直观对比不同预设的输出量级。
detailed与其它预设的取舍建议
| 预设 | 信息量 | 典型用途 |
|---|---|---|
none | 几乎为零 | 只需要 exit code / 错误码的静默构建 |
summary | 仅版本与错误/警告计数 | CI 里最简洁的健康检查 |
errors-only/errors-warnings | 仅错误(及警告) | 关注失败原因 |
minimal | 精简资产与错误摘要 | 日常开发默认输出之上的一档收敛 |
normal | webpack 默认输出 | 大多数场景的默认选择 |
detailed | 资产、chunk、模块、导出、bailout、内部日志全开 | 分析模块图、tree shaking / scope hoisting 失效原因、缓存命中 |
verbose | 在 detailed 基础上再开reasons、chunkModules、orphanModules等 | 最彻底的诊断,输出量最大 |
实际使用建议:日常构建用默认normal或minimal即可;当需要排查"某个模块为什么没被打包进预期 chunk""为什么某段代码没被摇树""scope hoisting 为何被降级"这类问题时,切到detailed,重点看模块条目下方的[no exports used]、with side effects与ModuleConcatenation bailout行,以及各LOG from ...分组的缓存统计。示例仓库把这些场景沉淀为可独立运行的最小案例(见 examples 目录下的stats-*系列),读者可直接对任意一个目录执行构建复现本文输出。
【免费下载链接】webpackA bundler for javascript and friends. Packs many modules into a few bundled assets. Code Splitting allows for loading parts of the application on demand. Through "loaders", modules can be CommonJs, AMD, ES6 modules, CSS, Images, JSON, Coffeescript, LESS, ... and your custom stuff.项目地址: https://gitcode.com/GitHub_Trending/web/webpack
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考