Analyzing build statistics is a good step towards understanding webpack better. The available tooling helps to answer the following questions:
To make webpack emit analysis information, you should set the --json
flag and pipe the output to a file as follows:
package.json
{
"scripts": {
"build:stats": "wp --mode production --json > stats.json"
}
}
The above is the basic setup you need, regardless of your webpack configuration. Execute npm run build:stats
now. After a while you should find stats.json at your project root. This file can be pushed through a variety of tools to understand better what's going on.
To capture timing-related information during the build, set `profile` to `true` in webpack configuration.
[0x](https://www.npmjs.com/package/0x) can generate a flamegraph of webpack execution to understand where time is spent.
Stats can be captured through Node. Since stats can contain errors, so it's a good idea to handle that case separately:
const webpack = require("webpack");
const config = require("./webpack.config.js")("production");
webpack(config, (err, stats) => {
if (err) {
return console.error(err);
}
if (stats.hasErrors()) {
return console.error(stats.toString("errors-only"));
}
console.log(stats);
});
To detect how webpack configuration is imported, use if (require.main === module)
kind of check to detect usage through Node. The idea is then to export the configuration (module.exports = getConfig;
) for if
and do module.exports = getConfig(mode);
for the else
clause.
The technique can be valuable if you want to do further processing on stats although often the other solutions are enough.
If you want JSON output from `stats`, use `stats.toJson()`. To get _verbose_ output, use `stats.toJson("verbose")`. It follows all stat options webpack supports.
To mimic the `--json` flag, use `console.log(JSON.stringify(stats.toJson(), null, 2));`. The output is formatted to be readable.
If you want to manage stats through a plugin, check out webpack-stats-plugin. It gives you control over the output and lets you transform it before writing. You can use it to exclude specific dependencies from the output.
webpack-bundle-tracker can capture data while webpack is compiling. It uses JSON for this purpose.
Webpack allows you to define a performance budget. The idea is that it gives your build size constraint, which it has to follow. The feature is disabled by default, and the calculation includes extracted chunks to entry calculation.
To integrate the feature into the project, adjust the configuration as below:
webpack.config.js
const productionConfig = merge([
...
{
performance: {
hints: "warning", // "error" or false are valid too
maxEntrypointSize: 50000, // in bytes, default 250k
maxAssetSize: 100000, // in bytes
},
},
]);
In case your project exceeds the limits, you should see a warning similar to below:
WARNING in entrypoint size limit: The following entrypoint(s) combined asset size exceeds the recommended limit (48.8 KiB). This can impact web performance.
Entrypoints:
main (131 KiB)
runtime.41f8.js
vendor.1622.js
main.aca1.css
main.eddd.js
If you want to enforce a strict limit in a CI environment, set hints
to error
. Doing this will fail the build in case it is reached and force the developers either go below the limit or raise a discussion about good limits.
It's possible to analyze bundle dependencies in a graphical manner, and many tools exist for this purpose:
Pie charts, treemaps, and command-line tools let you visualize bundle composition. Studying the generated graphics can generate insights and understand what's contributing to the bundle size.
Webpack Visualizer provides a pie chart showing your bundle composition, allowing to understand which dependencies contribute to the size of the overall result. Webpack Chart is another similar option.
In addition to providing a pie chart visualization, Auxpack is able to track bundle size over time.
webpack-bundle-analyzer provides a zoomable treemap.
source-map-explorer is a tool independent of webpack. It allows you to get insight into your build by using source maps. It gives a treemap based visualization showing what code contributes to the result. bundle-wizard is another similar tool.
webpack-bundle-size-analyzer emits a text based composition:
$ webpack-bundle-size-analyzer stats.json
react: 93.99 KB (74.9%)
purecss: 15.56 KB (12.4%)
style-loader: 6.99 KB (5.57%)
fbjs: 5.02 KB (4.00%)
object-assign: 1.95 KB (1.55%)
css-loader: 1.47 KB (1.17%)
<self>: 572 B (0.445%)
There are multiple plugins to make the webpack output easier to understand and more convenient:
webpack.ProgressPlugin
is included out of the box and can be used as well.It's possible to integrate bundle analysis to your build process by using Bundle Analyzer (free) and Packtracker (commercial). The services integrate well with GitHub and will show up in your pull requests, as it's valuable to have the information visible there.
There are multiple packages which let you compare webpack bundles over time:
unused-webpack-plugin is able to discover files that aren't used by the webpack build but are included to the project. remnants is a solution that goes beyond webpack and can be used with other tools as well.
There are multiple tools for finding duplicates in a project:
whybundled has been designed to answer the question why a specific module was included to the bundles. statoscope is a visual interface for the same purpose.
Set `stats.reasons` to `true` through webpack configuration to capture similar information.
When you are optimizing the size of your bundle output, these tools are invaluable. The official tool has the most functionality, but even basic visualization can reveal problem spots. You can use the same technique with old projects to understand their composition.
To recap:
You'll learn to tune webpack performance in the next chapter.
This book is available through Leanpub (digital), Amazon (paperback), and Kindle (digital). By purchasing the book you support the development of further content. A part of profit (~30%) goes to Tobias Koppers, the author of webpack.