Esbuild is a web bundler tool. According to the official site, it is much faster than other current build tools like webpack, rollup and Parcel. Here you will see how to use esbuild to bundle, minify JavaScript, CSS in Deno. The esbuild usage in Node is almost the same.
What is a bundler?
A bundler is a tool that bundles multiple scripts together into one script that is production-ready in the browser. It often performs transformations on the scripts and is able to bundle other static assets like images, CSS, ect.
The benefits of using a web bundler
- Help developers to manage dependencies.
- Minify file which saves bandwidth.
- Transform code to make your product available on more enrionments.
- Optimize the code to be more efficient.
- Help to optimize assets loading.
Features of esbuild
Main features:
- Extrem speed without needing a cache.
Esbuild is written in Go by which esbuild is fast. - JavaScript, CSS, TypeScript, and JSX built-in.
The content type can be:- JavaScript, TypeScript — Boundle, minify, transform (TypeScript to JavaScript, to Node or browser platform).
- JSX — Parse JSX to normal JavaScript.
- JSON — Parse JSON to JavaScript object.
- CSS — Boundle and minify a CSS file without importing it from JavaScript.
- Other type: text, binary, data URL, external file…
- Plugins are supported satisfy more needs.
Some pliugins like:- esbuild-mdx: A plugin to render .md and .mdx-delimited files as React components.
- esbuild-plugin-lit: Import and minify CSS, SVG, HTML, XLIFF files as tagged-template literals.
- esbuild-plugin-markdown: Import & bundle markdown files
Unsupported feature:
- ES5 is not supported
ES5 is not supported well: Transforming ES6+ syntax to ES5 is not supported yet (2023.07).
However, if you’re using esbuild to transform ES5 code, you should still set the target to es5 to prevent introducing ES6 syntax. - TypeScript type checking
Esbuild API
Esbuild provides two commonly-used API:
build
Takes one or more files and various options and writes the result back to the file system.transform
A limited special-case ofbuild
that transforms string of code in an isolated environment (like it works in the browser) and returns the result as string.
Esbuild provides differenct interface like CLI, JavaScript API and Go API/CLI. Here we check how to use esbuild API in JavaScript and focus on the build
API for the tranform
is similar.
Asynchonous and synchronous
You can use esbuild API in asynchonous and synchronous:
– Aync API
– The main advantage is you can use plugins with the asynchonous build
API (not with the transform
API).
– The main disadvantage is it does not work in situations that must be synchronous like require.extensions
.
– Sync API
– You can’t use plugins with the synchronous API since plugins are asynchronous.
Esbuild API — build
Minify a JavaScript file
An example to minify js-example.js
in Deno (A replacement for Node.js).
The js-example.js
:
const DEBUG = false;
function one() {
DEBUG && console.log('one');
}
function two() {
console.log('two');
}
one();
Our code:
import * as esbuild from 'https://deno.land/x/esbuild@v0.17.18/mod.js';
// Use build() method
async function minifyJs() {
await esbuild.build({
entryPoints: ['js-example.js'],
minify: true,
outfile: 'js-example-min.js',
});
console.log(Deno.readTextFileSync('js-example-min.js'));
// Output:
// const DEBUG=!1;function one(){}function two(){console.log("two")}
esbuild.stop(); // It is necessary in Deno environment.
}
minifyJs();
You may notice that the one();
is removed for the call actually do nothing. If we add bundle
option, the unused function function two() {...}
will be removed either. See the example in the next section.
Be aware to call esbuild.stop()
in Deno. According to Esbuild: Deno instead of node:
You need to call stop() when you’re done because unlike node, Deno doesn’t provide the necessary APIs to allow Deno to exit while esbuild’s internal child process is still running.
Minify a JavaScript with a more bundle
option
import * as esbuild from 'https://deno.land/x/esbuild@v0.17.18/mod.js';
// Use build() method
async function minifyJs() {
await esbuild.build({
entryPoints: ['js-example.js'],
bundle: true,
minify: true,
outfile: 'js-example-bundle-min.js',
});
console.log(Deno.readTextFileSync('js-example-bundle-min.js'));
// Output:
// (()=>{})();
esbuild.stop(); // It is necessary in Deno environment.
}
minifyJs();
More simplified, isn’t it?
Note
Esbuild does not boundle the multiple files occured in the entry points, it will create multiple separate files. To bundle multiple files, import them into one file use that file as entry point.
Bundle multiple JavaScript files into one
The main.js
:
import A from a.js;
import B from b.js;
...
The code:
import * as esbuild from 'https://deno.land/x/esbuild@v0.17.18/mod.js';
async function bundleJs() {
await esbuild.build({
entryPoints: ['main.js'],
bundle: true,
outfile: 'main.bundle.js',
});
esbuild.stop(); // It is necessary in Deno environment.
}
bundleJs();
Minify a CSS file
The main.css
:
:root {
--background-main: #333; /* Use a dark mode */
--text-main: #ccc;
}
body {
background: var(--background-main);
color: var(--text-main);
font-family: "Helvetica Neue", Helvetica, Arial, "MS Pゴシック";
}
.warning{
color: rgba(255, 0, 0, 0.5);
}
The code:
import * as esbuild from 'https://deno.land/x/esbuild@v0.17.18/mod.js';
function bundleAndMinifyCss() {
esbuild.buildSync({
entryPoints: ['main.css'],
bundle: true,
minify: true,
outfile: 'main.min.css',
});
console.log(Deno.readTextFileSync('main.min.css'));
// Output:
// :root{--background-main: #333;--text-main: #ccc}body{background:var(--background-main);color:var(--text-main);font-family:Helvetica Neue,Helvetica,Arial,ff2dff33 ff3030b430b730c330af}.warning{color:#ff000080}
esbuild.stop(); // It is necessary in Deno environment.
}
bundleCss();
You will see below things are done:
- The uncessary white spaces and
;
are removed; - The comments in CSS are removed;
- The non-ASCII characters are escaped in form of
xxxx
. - The color
rgba(255, 0, 0, 0.5)
is changed to#ff000080
.
Note
If you choose to use synchronous API
esbuildSync()
in Deno, you will see below error:
Error: The "buildSync" API does not work in Deno
Bundle a CSS file
Esbuild can bundle a CSS file which contains @import
other other CSS files and reference image and font files with url()
and esbuild will bundle everything together.
For image and font files, you need to configure a loader which is usually either the data URL loader or the external file loader.
Esbuild API — transform
Minify a JavaScript file
import * as esbuild from 'https://deno.land/x/esbuild@v0.17.18/mod.js';
async function minifyJs2() {
const src = Deno.readTextFileSync('js-example.js');
const { code } = await esbuild.transform(src, {
// bundle: true, // error: Invalid option in transform() call: "bundle"
minify: true,
});
console.log(code);
// Output:
// const DEBUG=!1;function one(){}function two(){console.log("two")}
esbuild.stop(); // It is necessary in Deno environment.
}
minifyJs2();
Note transform()
does not support bundle
option.
Transform TypeScript to JavaScript
mport * as esbuild from 'https://deno.land/x/esbuild@v0.17.18/mod.js';
async function tranformTsToJs() {
const ts = 'let x: number = 1';
let result = await esbuild.transform(ts, {
loader: 'ts',
});
console.log(result);
// Output:
// {
// warnings: [],
// code: "let x = 1;n",
// map: "",
// mangleCache: undefined,
// legalComments: undefined
// }
esbuild.stop();
}
tranformTsToJs();
Resource
- esbuild
- Modern Web Bundlers in 2023
- Vite — Dev server, build command to bundle code with Rollup.
- Webpack — Bundle JavaScript and static assets like images, CSS, fonts.
- Parcel (known for zero configuration) — Automatically detect and boundle all assests and dependencies without configuration.
- SWC — Work for JavaScript/TypeScript, compile, bundle, minify, transform and more. Used by Next.js, Parcel, Deno.
- Rollup — Bundle JavaScript code.