Library / SDK
stephencookdev/speed-measure-webpack-plugin avatar
stephencookdev/speed-measure-webpack-plugin

Speed Measure Webpack Plugin: measuring loader and plugin time in webpack builds

⏱ See how fast (or not) your plugins and loaders are, so you can optimise your builds

2,439 stars79 forksJavaScriptMIT

At a glance

What is it?
Speed Measure Webpack Plugin wraps a webpack config and reports how long each plugin and loader took. It is a diagnostic tool for people who already have a slow build and need to know which part to fix.
Who is it for?
Adopt it if you have a webpack build that has become slow and you need per-plugin and per-loader numbers before changing anything. Skip it if your build runs on Vite, esbuild or rspack, or if you need per-loader attribution inside thread-loader or file-loader, which the README lists as inaccurate under granularLoaderData.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Activity is slowing. The repository last received commits 6 months ago.
What is it written in?
Mainly JavaScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 2, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The problem Speed Measure Webpack Plugin solves

A slow webpack build gives you one number: total time. That number does not tell you whether the cost sits in a minifier, a CSS extractor, a TypeScript loader, or in webpack reading files off disk. Optimising without that split is guesswork, and the usual result is that someone disables a plugin, reruns the build, and cannot tell whether the change mattered or the machine was just warmer.

Speed Measure Webpack Plugin, usually shortened to SMP, exists to produce that split. The README frames it plainly: "The first step to optimising your webpack build speed, is to know where to focus your attention." It measures the build and prints timing output to the console by default.

The audience is narrow and specific. You need an existing webpack build, a config you can edit, and a reason to care about build duration (a CI pipeline that times out, a dev server that takes too long to start, a watch loop that feels sluggish). SMP is a measurement instrument, not a build accelerator. It does not cache, parallelise or replace anything. If your build is already fast enough, there is nothing here for you.

How SMP wraps your config and where the timings come from

SMP works by interception rather than by hooking into webpack's internal stats. You pass your config object to smp.wrap(), and the plugin returns a new config in which each plugin has been replaced by a proxy that records entry and exit times. The repository layout reflects this: there is a WrappedPlugin/ directory alongside index.js, loader.js, output.js, utils.js and colours.js. The wrapping happens at config-construction time, which is why the change to your config is a single call rather than a webpack plugin entry in the plugins array.

Loader timing works differently. By default SMP measures loaders in groups. When you turn on granularLoaderData, the README states that SMP prepends its timing loader to each matching loader rule, which is what produces per-loader numbers. That prepending is also the source of the option's accuracy caveats.

Output is assembled in output.js and formatted according to outputFormat. The default is "human". "json" produces a JSON blob, "humanVerbose" produces a more verbose human-readable version, and passing a function calls that function with the JSON blob. outputTarget defaults to console.log, but a string is treated as a file path and a function receives the output as its first parameter. That is the whole data flow: wrap, time, format, emit.

Installing Speed Measure Webpack Plugin and measuring a first build

Install it as a dev dependency. The README gives both package managers:

bash
npm install --save-dev speed-measure-webpack-plugin

or

bash
yarn add -D speed-measure-webpack-plugin

The package requires at least Node v6 and accepts webpack 1 through 5, according to the README and the peerDependencies field in package.json, which reads "^1 || ^2 || ^3 || ^4 || ^5".

Now change your webpack config. The README shows the before and after. Before, the config is a plain object:

javascript
const webpackConfig = {
  plugins: [new MyPlugin(), new MyOtherPlugin()],
};

After, you require SMP, construct it, and pass the same object to wrap():

javascript
const SpeedMeasurePlugin = require("speed-measure-webpack-plugin");

const smp = new SpeedMeasurePlugin();

const webpackConfig = smp.wrap({
  plugins: [new MyPlugin(), new MyOtherPlugin()],
});

Run your build as normal. The README states that SMP will now be printing timing output to the console by default. You should see a breakdown listing each plugin and loader with the time attributed to it, plus a general output figure and a count of modules without loaders.

If you do not want measurement on every run, the README documents an opt-in pattern using the disable option: `{ disable: !process.env.MEASURE }`, which lets you run `MEASURE=true npm run build` when you want numbers.

Granular loader data is experimental, and the README says why

The most useful option for loader-level work is also the least trustworthy. granularLoaderData defaults to false, and the README marks it experimental with a direct warning: loaders using separate processes, naming thread-loader as the example, and loaders emitting file output, naming file-loader, will have inaccurate results.

The reason follows from the mechanism. SMP attributes time by prepending its own timing loader to the rule, so it measures the span during which its loader was in the chain. A loader that hands work to a worker pool returns before the work finishes, and a loader that writes files spends time outside the measured span. The README states the maintainers intend to find solutions before removing the experimental flag.

There is a companion option, excludedLoaders, that takes an array of strings or regular expressions. When granularLoaderData is enabled, SMP skips rules whose loader chain contains a matching loader name or regular expression. String matching checks both the original loader request and the normalized package name. The README's example excludes "thread-loader" and /mini-css-extract-plugin/, which is a sensible default posture: exclude the loaders whose numbers you already know are wrong rather than reading them and drawing conclusions.

Naming plugins, excluding them, and comparing builds over time

SMP derives plugin names through plugin.constructor.name. The README acknowledges this does not work for some plugins. The pluginNames option maps an alias to a plugin constructor so the output reads sensibly. Note the shape of the README's example: the key is the custom name and the value is the plugin instance, not the other way round, which is easy to get backwards.

excludedPlugins takes an array of strings, constructors or regular expressions, and removes those plugins from SMP's proxy wrapping entirely. Name matching checks both pluginNames aliases and constructor names. Excluding a plugin is not just cosmetic: it removes the proxy, so a plugin that misbehaves under wrapping can be taken out of measurement without being removed from the build.

compareLoadersBuild is the option with the longest horizon. It takes a required filePath, and the README describes it as giving a comparison over time of module count and time spent per loader, providing more data when outputFormat is "humanVerbose". In practice this means you commit or retain a JSON file between builds and read the deltas. That is a different workflow from a one-off measurement, and it is the only part of SMP that assumes you keep historical data around.

loaderTopFiles defaults to 0 and, when set with outputFormat: "humanVerbose", includes the files taking the most time per loader. Setting it to 10 shows the top ten files per loader, per the README.

Where SMP is the wrong tool, and what to use instead

SMP only measures webpack. The peerDependencies field pins webpack 1 through 5, and nothing in the repository suggests a bundler-agnostic mode. If your project has moved to Vite or esbuild, SMP has nothing to wrap. Those tools report their own timing through their own build output and plugins, and their architectures differ enough that a webpack plugin cannot be ported by configuration alone.

Within webpack, the honest limitation is attribution. The README's own FAQ concedes that "general output time" is anything outside what SMP can actually measure, attributing it mostly to webpack reading from the file system. So a build where most of the wall clock sits in that bucket will produce a report full of small numbers and one large unexplained one. That is a real outcome, not a bug, and it means SMP answers "which plugin is slow" better than it answers "why is the build slow".

A different approach worth comparing is webpack's own profiling output, which reports per-module and per-chunk timing from inside the compiler rather than by wrapping config objects. The difference matters: SMP's proxy approach can be applied to any plugin without the plugin cooperating, but it measures the wrapper's view of the plugin, while compiler-level profiling measures what the compiler actually did. If a plugin number looks implausible, that gap is the first thing to suspect.

Maintenance, versioning and licence

The repository is not archived. The last push was on 2026-03-24, the same date as the v1.6.0 release. The previous release, v1.5.0, is dated 2021-03-28, so the gap between v1.5.0 and v1.6.0 is roughly five years. That pattern is worth reading carefully: the project is not abandoned, but releases are infrequent, and the README credits 18ways as the current maintainer rather than the original author alone.

The README states that SMP follows semver and points to migration.md for major-version upgrades. That file exists at the repository root. The practical upgrade cost is low for a dev dependency whose surface is one wrapper call and a handful of constructor options, but the migration guide is the place to check before crossing a major boundary, since plugin and loader wrapper behaviour is exactly the kind of thing a major version can change.

The licence is MIT, declared in package.json and present as a LICENSE file at the root. MIT is permissive: you can use, modify and redistribute the package, including in commercial and closed-source projects, provided the copyright notice and permission notice are retained. That is a summary of the licence text, not legal advice; read LICENSE yourself if the distinction matters to your organisation.

The runtime dependency list is short. package.json lists chalk as the only dependency, which is what colours.js uses for terminal output. Everything else in devDependencies (alex, husky, lint-staged, prettier, write-good) is tooling for the repository itself. The package also declares a packageManager of [email protected] and a devEngines requirement of Node 18 or higher for working on the repository, while the published package still supports Node 6 and up.

Editorial conclusion

Adopt it if you have a webpack build that has become slow and you need per-plugin and per-loader numbers before changing anything. Skip it if your build runs on Vite, esbuild or rspack, or if you need per-loader attribution inside thread-loader or file-loader, which the README lists as inaccurate under granularLoaderData. Before trusting a run, verify that plugin names resolve correctly through pluginNames, since the default comes from plugin.constructor.name and the README states that does not work for every plugin.

Frequently asked questions

What is webpack and why is it used?

Speed Measure Webpack Plugin does not explain webpack itself. It only measures webpack builds, and its README assumes you already have a webpack config to wrap.

Is webpack still relevant?

Speed Measure Webpack Plugin still declares support for webpack 1 through 5 in its peerDependencies, and the last push to its repository was on 2026-03-24. Whether webpack as a whole remains relevant is outside what the project documents.

Which is faster, Vite or webpack?

Speed Measure Webpack Plugin publishes no benchmark comparing the two. It only wraps webpack configs, so it cannot produce numbers for a Vite build.

Is esbuild faster than webpack?

Speed Measure Webpack Plugin gives no such comparison. It measures webpack plugins and loaders, and nothing in the repository suggests it can measure an esbuild build.

Official sources

  1. Issues
  2. License: MIT
  3. README
  4. Releases
  5. stephencookdev/speed-measure-webpack-plugin on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/stephencookdev-speed-measure-webpack-plugin.svg)](https://hysenlabs.com/projects/stephencookdev-speed-measure-webpack-plugin)