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
orts-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.
Top comments (0)