26
How to build a multipage website with esbuild
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.
There are multiple reasons you would like to do it. You can have multiple single-page apps in one repository and share the build setup to speed things up. Another reason would be to make sure the build creates chunks that are reusable between apps. Or, you have a legacy HTML+JS application with many HTML files & you want to keep separate JS for each of them.
First, we have 2 simple HTML files on the top level of the project:
a.html
:
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>A part of our website</title>
<link rel="shortcut icon" href="#" />
<div id="view"></div>
<script type="module" src="./dist/a.js"></script>
</head>
<body>
<h1>Page A</h1>
<p id="core"></p>
<p id="a">(a placeholder)</p>
<p id="b">(b placeholder)</p>
<p><a href="b.html">Go elsewhere</a></p>
</body>
</html>
b.html
:
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>B part of our website</title>
<link rel="shortcut icon" href="#" />
<div id="view"></div>
<script type="module" src="./dist/b.js"></script>
</head>
<body>
<h1>Page B</h1>
<p id="core"></p>
<p id="a">(a placeholder)</p>
<p id="b">(b placeholder)</p>
<p><a href="a.html">Go elsewhere</a></p>
</body>
</html>
Each of the files imports its JS file, and as we are using ESM output, we need to import it with <script type="module" ...
. All paragraphs <p id="...
are meant to be updated by our JS & to let us see if all works as expected.
We have 3 simple files for testing our setup. Each file is using jQuery, so we can see if the chunks are created as expected - with the big library included in the shared file, and individual files small.
Besides that, the files are rather trivial
./src/core.js
:
import $ from "jquery";
$("#core").html("Core module");
./src/a.js
:
import $ from "jquery";
import "./core";
$("#a").html("A file, file A");
./src/b.js
:
import $ from "jquery";
import "./core";
$("#b").html("B yourself");
Before installing the dependencies, let's first create an npm package:
$ npm init -y
Wrote to /home/marcin/workspace/github/esbuild-multipage/package.json:
{
"name": "esbuild-multipage",
"version": "1.0.0",
"description": "Example repo for an article about multipage with esbuild",
"main": "index.js",
...
Then you can install your dependencies with:
$ npm install --save jquery esbuild
added 2 packages, and audited 3 packages in 826ms
found 0 vulnerabilities
The build script is similar to what I used in the lazy loading example. If your configuration becomes more complicated, at some point will make sense to move it to a build script - as I show here.
To have your build available with npm run build
, add to package.json
:
{
...
"scripts": {
...
"build": "esbuild src/a.js src/b.js --bundle --outdir=dist --splitting --format=esm"
}
...
The values in the command:
-
src/a.js
&src/b.s
- the entry points of the application -
--bundle
- bundle mode of esbuild -
--outdir=dist
- the folder where all the built code goes -
--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 output
Splitting - making shared chunks for our entry points to share - is still work-in-progress. You can read more about it in (the documentation)[https://esbuild.github.io/api/#splitting]. If you get into trouble because of it, just remove --splitting
from the build command.
So, how is our code doing in the end:
$ npm run build
> [email protected] build
> esbuild src/a.js src/b.js --bundle --outdir=dist --splitting --format=esm
dist/chunk-TTCANJWN.js 226.2kb
dist/a.js 190b
dist/b.js 186b
⚡ Done in 23ms
Pretty sweet I would say!
In this article, we have seen how to build a multipage website with esbuild. Stay tuned for other esbuild & javascript articles.
26