How to lazy load with esbuild
I'm JS developer with 13 years of professional experience. I'm always happy to teach my craft.
Search for a command to run...
I'm JS developer with 13 years of professional experience. I'm always happy to teach my craft.
No comments yet. Be the first to comment.
In this series, I'll take a look on different aspects of esbuild - a fast js bundler.
In this article, I will show how to set a simple multipage website with esbuild. The code used here is similar to the one I used in this webpack 5 example, so you can use those two articles to compare both bundlers - in both speed & ease of use. Use ...
I’ve been working in programming for the last 16 years. Let’s see what changes I see in our industry that are enabled by generative AI. Rapid prototyping The last few months, I’ve been working on a set of WordPress plugins, related to event organizat...
Writing unit tests takes time and effort. Nonetheless, many teams insist on writing them anyway—that’s because of the benefits they bring to a project. Those benefits are mainly the following: fast feedback—unit tests speed up each iteration of twea...

Pure functions are the perfect case for unit testing. For a given input, we always expect the same output—there is no internal state involved. Let’s take a look at a few examples and some simple tests that check if the methods work as expected. Jasmi...

Let’s say you have a job interview in a few days. How should you prepare for it so that you can make an informed decision about joining the company, as well as make sure that your interests are taken care of? Prepare your questions An interview is a ...

Creating example projects is a common way of showing your skills to potential employers. Let’s take a look at what’s important to keep in mind when building personal projects with an eye toward impressing prospective employers. Simplicity Building ap...

In this article, I will show you how to lazy load with esbuild. It's achieved by using a work-in-progress flag --splitting, so you may want to check out the documentation before you will start building something very complex with it.
Is a pattern of delaying the download of a resource until it's needed. A common approach in web applications is to split critical & non-critical code into different files. In this way, non-critical code can be lazy-loaded in the background, while the user has already access to most of the features of the app.
Similar to what I used in the webpack example, here we will have a simple js application, that happens to depend on a big, 3rd party library. The library I use, PDF-LIB was already discussed in an earlier post. PDF creation is a complex task, which requires a lot of code. Let's imagine an invoice application - one that allows for creating invoices & generating PDFs. it's an important feature of an application, but only called from some route & even there not needed immediately.
For the example application, I have few files. index.html:
<!-- index.html -->
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>Lazy load in esbuild</title>
<link rel="shortcut icon" href="#" />
<div id="view"></div>
<script type="module" src="./dist/index.js"></script>
</head>
<body></body>
</html>
Simple loading the builts JS from the dist folder.
src/index.js:
const view = document.getElementById("view");
view.innerHTML = `<button id="pdf-button">Generate PDF</button>
<br>
<iframe id="pdf" style="width: 350px; height: 600px"></iframe>`;
import("pdf-lib").then(({ PDFDocument }) => {
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;
});
});
In this one file, we have 2 sections that will be executed in a different moments. The first 2 lines are run immediately after loading the js. They have our critical path - they set up the view for the user to interact with, while we load the rest of JS. The other is the callback for the dynamic import of pdf-lib. You can read more about dynamic imports on mdn, but in short, they are a part of the es-module specification. In short - it's loading another file during the runtime, and resolving a promise when it's available.
For the best user experience, you could set the Generate PDF button inactive here, and turn it active after PDF-LIB is available. For the sake of simplicity of the example code, I left the button unresponsive while the library loads.
After initializing your package with:
$ npm init -y
you can install all dependencies with:
$ npm install --save esbuild pdf-lib
You can add the build CLI command as an npm script to package.json:
{
...
"scripts": {
...
"build": "esbuild src/index.js --bundle --outdir=dist --splitting --format=esm"
}
...
The values we have here:
src/index.js - the entry point of the application--bundle - we tell the esbuild to bundle the whole application--outdir=dist - because of using splitting, just specifying the output file with --outfile is not enough - esbuild needs directory to put all chunks it creates there--splitting - we turn on the experimental splitting behavior--format=esm - another requirement of splitting to work - as of now, it's only working with es-modules outputYou can check out my course about esbuild.
After all this, our application will lazy load the big 3rd party dependency:

If you want to see it in action yourself, the application is available here, and the source code: