StephenCookDev

⏱ Announcing SMP: Speeding Up webpack With Timers Measure the Speed of Your webpack Loaders and Plugins

Posted on by Stephen Cook

Measuring may not be the sexiest part of going fast, but it’s an important one. That’s why I’m excited to announce the Speed Measure Plugin for webpack, that I’ve been working on. Super easy to use, and compatible with all loaders and plugins by default — it’s available to use now, from GitHub and npm.

SMP logo

Just changing your webpack config from { plugins: [new XPlugin()] } to smp.wrap({ plugins: [new XPlugin()] }) — gives you console output like this:

Preview of console output from SMP

Knowing which plugins and loaders are causing lag is half the battle — the other half is cutting out or trimming down the parts that are slowing you down.

Using SMP

So how do we use the plugin? And how will that ultimately help us to speed up our webpack build?

Let’s look at a basic example — imagine we have the following webpack config:

const ForceCaseSensitivityPlugin = require("force-case-sensitivity-webpack-plugin");
const ManifestPlugin = require("webpack-manifest-plugin");

module.exports = {
  entry: {
    app: ["./app.js"]
  },
  output: "./public",
  module: {
    rules: [
      {
        test: /.js$/,
        use: [{ loader: "babel-loader" }]
      },
      {
        test: /.coffee$/,
        use: [{ loader: "coffee-loader" }]
      }
    ]
  },
  plugins: [
    new ForceCaseSensitivityPlugin(),
    new ManifestPlugin()
  ]
};

As it stands, webpack will tell us that our build takes however long overall. But from there on, other than adding/removing plugins and loaders to see how that number changes, we don’t know which parts are taking the longest.

So let’s first add SpeedMeasurePlugin. To do this, we need to change our webpack config to something like this:

const ForceCaseSensitivityPlugin = require("force-case-sensitivity-webpack-plugin");
const ManifestPlugin = require("webpack-manifest-plugin");
const SpeedMeasurePlugin = require("speed-measure-webpack-plugin");

const smp = new SpeedMeasurePlugin();

module.exports = smp.wrap({
  entry: {
    app: ["./app.js"]
  },
  output: "./public",
  module: {
    rules: [
      {
        test: /.js$/,
        use: [{ loader: "babel-loader" }]
      },
      {
        test: /.coffee$/,
        use: [{ loader: "coffee-loader" }]
      }
    ]
  },
  plugins: [
    new ForceCaseSensitivityPlugin(),
    new ManifestPlugin()
  ]
});

And that’s it! By default, SMP will now start printing timing output to your console (you can also disable SMP entirely with a flag).

Now let’s have a look at the plugins section of our output, which should look something like this:

ForceCaseSensitivityPlugin took 4.21 secs
ManifestPlugin took 0.11 secs

So immediately we see that the force-case-sensitivity-webpack-plugin is taking an inordinately large amount of time for what it’s doing (just comparing case-sensitivity of require statements). And indeed, looking at the GitHub page, the author has actually archived the project in favour of case-sensitive-paths-webpack-plugin, because of performance issues. So let’s give that plugin a spin, instead.

CaseSensitivePathsPlugin took 0.32 secs
ManifestPlugin took 0.12 secs

A pretty noticeable improvement!

So that’s the plugins, how about the loaders?

babel-loader took 21.51 secs
  module count = 150
coffee-loader took 5.52 secs
  module count = 21
modules with no loaders took 3.13 secs
  module count = 143

First of all, what’s modules with no loaders? Not all modules get piped through webpack through a named loader (e.g. plain ol’ JS files from node_modules) — the timings of these modules goes under this modules with no loaders section.

Second of all, what’s a module? Each file or fragment that gets loaded into webpack (usually via a loader) is called a “module”. In most cases, you can just think of this as a file that you’re require ing somewhere in your code. You can read more about it in the official webpack docs, if you want a more in depth explanation.

So, in this example we can see that the coffee-loader is taking 5.52s for just 21 files. These coffeescript files have probably just never been ported because no-one wanted to touch some legacy code, and they weren’t doing any harm.

But looking at how long they’re taking in the grand-scheme of things, it might well by worth porting them now to vanilla JS.

babel-loader took 24.41 secs
  module count = 171
modules with no loaders took 3.13 secs
  module count = 143

Much better!

And if you’re struggling to compare these results in your workspace, more explicit statistical information (such as mean, median, and standard deviation of time) are available in humanVerbose mode — as explained in the section about options.outputFormat in the README.

Hopefully this glimpse into what SMP can give you has been helpful!

Give it a Spin!

SMP is ready to go, so please — try it out, and see where your webpack build is dragging its feet!

Let me know how you get on, and don’t be shy about raising issues or requests!