How to speed up webpack with esbuild-loader

If you are a webpack user and have heard about esbuild speed, you may start questioning your js-bundler choices. Luckily, you don't have to drop your hand-crafted webpack config just now. Thanks to esbuild-loader, you can get part of the speed improvement without doing a whole migration.
Benchmark repo
For checking the esbuild-loader with a non-trivial amount of code, I created a repository. My code is minimal, src/index.js:
import { PDFDocument } from "pdf-lib";

const pdfButton = document.getElementById("pdf-button");

pdfButton.addEventListener("click", async () => {
  const pdfDoc = await PDFDocument.create();
  const page = pdfDoc.addPage([350, 400]);
  page.moveTo(110, 200);
  page.drawText("Hello World!");
  const pdfDataUri = await pdfDoc.saveAsBase64({ dataUri: true });
  document.getElementById("pdf").src = pdfDataUri;
});
index.html:
<!DOCTYPE html>

<html>
  <head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8" />
    <title>esbuild-loader pdf-lib</title>
    <link rel="shortcut icon" href="#" />
  </head>
  <body>
    <button id="pdf-button">Generate pdf</button>

    <br />

    <iframe id="pdf" style="width: 350px; height: 600px"></iframe>

    <script type="text/javascript" src="dist/main.js"></script>
  </body>
</html>
and it does mainly 2 things:
  • loads pdf-lib - pure js pdf library, so our build has something to spend time on
  • provides some operation we can execute to see if the built code works as expected
  • Standard webpack build
    This code is meant to be built with the default webpack configuration. If you checkout the webpack branch, the build will go more or less like this:
    $ npm run build
    
    > esbuild-loader-pdf-lib@1.0.0 build
    > webpack --mode=production
    
    asset main.js 413 KiB [compared for emit] [minimized] [big] (name: main) 1 related asset
    orphan modules 936 KiB [orphan] 156 modules
    runtime modules 663 bytes 3 modules
    cacheable modules 1.12 MiB
      modules by path ./node_modules/pako/lib/zlib/*.js 183 KiB 11 modules
      modules by path ./node_modules/pako/lib/utils/*.js 7.56 KiB
        ./node_modules/pako/lib/utils/common.js 2.39 KiB [built] [code generated]
        ./node_modules/pako/lib/utils/strings.js 5.17 KiB [built] [code generated]
      modules by path ./node_modules/pako/lib/*.js 22.9 KiB
        ./node_modules/pako/lib/deflate.js 10.8 KiB [built] [code generated]
        ./node_modules/pako/lib/inflate.js 12.1 KiB [built] [code generated]
      ./src/index.js + 155 modules 937 KiB [built] [code generated]
      ./node_modules/pako/index.js 347 bytes [built] [code generated]
    
    WARNING in asset size limit: The following asset(s) exceed the recommended size limit (244 KiB).
    This can impact web performance.
    Assets: 
      main.js (413 KiB)
    
    WARNING in entrypoint size limit: The following entrypoint(s) combined asset size exceeds the recommended limit (244 KiB). This can impact web performance.
    Entrypoints:
      main (413 KiB)
          main.js
    
    
    WARNING in webpack performance recommendations: 
    You can limit the size of your bundles by using import() or require.ensure to lazy load some parts of your application.
    For more info visit https://webpack.js.org/guides/code-splitting/
    
    webpack 5.45.1 compiled with 3 warnings in 5983 ms
    Key numbers to remember:
  • complication time - almost 6s
  • output size - 413 KiB
  • esbuild-loader enhanced build
    esbuild-loader provides 2 ways of using esbuild in webpack:
  • as a loader that can replace babel-loader or ts-loader
  • ESBuildMinifyPlugin that we can use to replace the default terser plugin
  • I haven't seen any improvements in my example repo by using the loader in my example repo - it even got a bit slower. Luckily, the minification improvements are interesting enough to recommend you to give it a try. You need webpack.config.js with:
    const { ESBuildMinifyPlugin } = require("esbuild-loader");
    
    module.exports = {
      mode: "production",
      optimization: {
        minimizer: [
          new ESBuildMinifyPlugin({
            target: "es2015", // Syntax to compile to (see options below for possible values)
          }),
        ],
      },
    };
    install esbuild-loader with:
    $ npm install --save-dev esbuild-loader
    and your build will look like this:
    $ npm run build          
    
    > esbuild-loader-pdf-lib@1.0.0 build
    > webpack --mode=production
    
    asset main.js 426 KiB [compared for emit] [minimized] [big] (name: main)
    orphan modules 936 KiB [orphan] 156 modules
    runtime modules 663 bytes 3 modules
    cacheable modules 1.12 MiB
      modules by path ./node_modules/pako/lib/zlib/*.js 183 KiB 11 modules
      modules by path ./node_modules/pako/lib/utils/*.js 7.56 KiB
        ./node_modules/pako/lib/utils/common.js 2.39 KiB [built] [code generated]
        ./node_modules/pako/lib/utils/strings.js 5.17 KiB [built] [code generated]
      modules by path ./node_modules/pako/lib/*.js 22.9 KiB
        ./node_modules/pako/lib/deflate.js 10.8 KiB [built] [code generated]
        ./node_modules/pako/lib/inflate.js 12.1 KiB [built] [code generated]
      ./src/index.js + 155 modules 937 KiB [built] [code generated]
      ./node_modules/pako/index.js 347 bytes [built] [code generated]
    
    WARNING in asset size limit: The following asset(s) exceed the recommended size limit (244 KiB).
    This can impact web performance.
    Assets: 
      main.js (426 KiB)
    
    WARNING in entrypoint size limit: The following entrypoint(s) combined asset size exceeds the recommended limit (244 KiB). This can impact web performance.
    Entrypoints:
      main (426 KiB)
          main.js
    
    
    WARNING in webpack performance recommendations: 
    You can limit the size of your bundles by using import() or require.ensure to lazy load some parts of your application.
    For more info visit https://webpack.js.org/guides/code-splitting/
    
    webpack 5.45.1 compiled with 3 warnings in 1658 ms
    Key values:
  • complication time - below 2s
  • output size - 426 KiB
  • So we got our build time about 3 times lower, with a 3% increase in build size.
    Links
    Summary
    If you are interested in speeding up your build time but have no time for replacing the whole bundler & the setup, ESBuildMinifyPlugin from esbuild-loader can be a good way to achieve that.

    40

    This website collects cookies to deliver better user experience

    How to speed up webpack with esbuild-loader