What is esbuild?
Tags: esbuild, javascript, typescript, css
Published: 2021-03-19 07:56:00

**Table of contents**

- [JavaScript’s dirty little secret](#javascripts-dirty-little-secret)
- [ES Modules](#es-modules)
- [Introducing esbuild](#introducing-esbuild)
- [Bundling](#bundling)
- [Plugins](#plugins)
- [Incremental compilation](#incremental-compilation)
- [Watch mode](#watch-mode)
- [Serve mode](#serve-mode)
- [Caveats](#caveats)
- [Conclusion](#conclusion)

---

By now you may have heard of esbuild -- _but what the hell is it_?

esbuild is an exciting new technology, I say as someone who has been building on esbuild for months. As [Evan W.](https://github.com/evanw) describes it, the creator of esbuild and co-founder of Figma, _esbuild is a linker for the web_. But what does that actually mean, and why should you care?

Well, JavaScript has a dirty little secret, and that is that you largely can’t deploy JavaScript to the web without tooling. Why is that?

### JavaScript’s dirty little secret

JavaScript is an interpreted language. Unlike systems languages like C, C++, and Go, you don’t ‘compile‘ JavaScript to machine code. Instead, JavaScript is evaluated as plaintext at runtime, which also makes JavaScript unbelievably error-prone.

The benefits of a compiler are generally a) performing static type-checking at build-time and b) building to one binary or one binary per operating system. This is simple and elegant and easy to reason about, although perhaps makes it harder to debug runtime errors.

But JavaScript doesn’t work this way. As most of you know, when you ‘deploy JavaScript’, that generally means linking plaintext JavaScript by way of the `<script>` tag. This is the happy path for one-off scripts, but what about for the case when you have many files and or dependencies?

### ES Modules

These days you can get away with something called [ES Modules](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules), which are a way of letting the browser worry about interlinking JavaScript dependencies. ES Modules simply means JavaScript modules, and a JavaScript module can be thought of as a ‘reusable unit of JavaScript’ that the browser evaluates and dynamically links at runtime. The difference here is that we use the `<script type="module">` tag instead of `<script>`. This is a step up over `<script>` but is far from complete.

The reason why ES Modules, convenient as they may be, are generally still not preferred for production is because they -- by design -- defer resolving JavaScript dependencies to runtime. If we could instead do that work ahead of time, it turns out we get better performance gains and [backwards compatibility](https://caniuse.com/es6-module), but this comes with a complexity cost and a learning curve.

This is why linkers are important. A linker is a class of tooling that ‘links’ your code for you so you can worry about the thing you actually care about. Without a linker, you would need to do all the work of stitching your code together in a way that you and your browser, and your users’ browsers, can understand. But we can do better than that! We can use tools like [webpack](https://github.com/webpack/webpack), [Rollup](https://github.com/rollup/rollup), [Parcel](https://github.com/parcel-bundler/parcel), or [esbuild](https://github.com/evanw/esbuild) to automate resolving dependencies at build-time.

So why emphasize esbuild -- what’s new or different about esbuild?

### Introducing esbuild

esbuild is a CLI, [NPM package](https://npmjs.com/package/esbuild), and [Go module](https://pkg.go.dev/github.com/evanw/esbuild/pkg/api) that makes bundling JavaScript accessible and fast. It is the brainchild of [Evan W.](https://github.com/evanw) and is implemented in Go and JavaScript / TypeScript. It was first released early 2020, and is now 0.9.x (as of early 2021).

esbuild has [exhaustive documentation](https://esbuild.github.io), a highly discoverable CLI experience, and is _extremely fast_. But what makes esbuild great is how well it solves for a well-defined, constrained problem space.

So what can you use esbuild for?

You can use esbuild to quickly link your JavaScript (`js`, `jsx`, `ts`, and `tsx`) and CSS dependencies as deployable assets for the web. And you can do so with [bundling or code-splitting](#bundling), [plugins](#plugins), and more. And what makes esbuild such a quality-of-life tool for me personally is that it implements [incremental compilation](#incremental-compilation), [watch mode](#watch-mode), and [serve mode](#serve-mode).

There’s a lot to unpack there. I’ll iterate each point now:

### Bundling

You can bundle or code-split your JavaScript and CSS sources.

- Bundling is for when you want to deploy a single `app.js` target.
- Code-splitting is for when you want to code-split `app.js` into many targets, such as `Sidebar.js`, `Header.js`, etc. Note that this assumes support for ES Modules.

[Docs here.](https://esbuild.github.io/api/#bundle)

### Plugins

The plugin API allows you to preprocess files as they are linked. This is incredibly useful if you want to convert Markdown to HTML or JSX, Sass to CSS, etc. The plugin API defers these implementation details to you.

See the [community repo](https://github.com/esbuild/community-plugins) for plugin ideas.

[Docs here.](https://esbuild.github.io/plugin)

### Incremental compilation

Incremental compilation means if you need to compile the same file repeatedly, say for example, as your sources change, you can do so without incurring a performance penalty. This is because esbuild only performs work on changed sources, rather than bundling or code-splitting from scratch every time.

[Docs here.](https://esbuild.github.io/api/#incremental)

### Watch mode

Watch mode means esbuild can ‘pick up‘ changes to your source code as they occur. This means that you don’t need to worry about file-watchers or libraries like [nodemon](https://npmjs.com/package/nodemon) or [chokidar](https://npmjs.com/package/chokidar); you can offload this work to esbuild and even implement your own watch handlers so you can observe events, log them, push [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events) or [WebSockets](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket), etc.

[Docs here.](https://esbuild.github.io/api/#watch)

### Serve mode

Serve mode means you can use esbuild as a web server and implement your own serve handler for incoming requests, again to observe events, log them, etc. esbuild actually serves your bundled or code-split targets from memory, rather than from disk. This makes esbuild an incredibly performant web server because it reduces the amount of total work needed per request.

[Docs here.](https://esbuild.github.io/api/#serve)

---

### Caveats

Now, let’s talk about caveats. 😱

**esbuild is pre-1.0 software and not yet feature complete.**

- My experience has demonstrated that this is not a cause for concern. The creator is incredibly mindful about what needs to change, why, and carefully documents every meaningful change in the [changelog](https://github.com/evanw/esbuild/blob/master/CHANGELOG.md), even unreleased changes.

**esbuild does not perform static type-checking.**

- This is hardly a caveat since esbuild is a bundler, not a compiler in the conventional sense, but you can just as well plug `flow` or `tsc` into your build pipeline if static type-checking is important to you. (I don’t do this because I rely on VS Code alone for type-checking.)
- It’s worth mentioning that esbuild does log errors, warnings, and hints which can help you catch some errors, but these are generally syntactic errors.

**esbuild is largely a one-man show.**

- This can be interpreted as either a strength or a weakness, but I see this as a strength because esbuild as a technology is _incredibly focused_. It doesn’t try to solve every problem -- rather, a well-defined, constrained problem space that most frontend developers have or will experience.
- If you take a look at the [issues](https://github.com/evanw/esbuild/issues), you’ll notice almost every issue has been addressed by community members or Evan, the creator. Development is pretty rapid and there’s generally a minor release once or twice a week.

**esbuild is somewhat at odds with the Babel ecosystem.**

- Babel helped modernize JavaScript by enabling developers to write tomorrow’s code today, and that was necessary when JavaScript was underpowered. But today’s JavaScript is far more powerful and expressive than the yesteryears of JavaScript, so I don’t personally see this as a caveat.
- While you may want or need Babel for the latest and greatest CSS-in-JS library, I believe you can still implement whatever additional tooling you may need as a plugin. And if not, that may be a condition for when to not use esbuild.

**esbuild supports many, many options.**

- The main APIs are roughly only `transform`, `build`, and `serve`, but the options these functions support are lengthy. Don’t worry if you don’t understand every option’s use-case; I don’t understand all of them.
- Note that esbuild’s CLI logger is extremely helpful. You can get very far with experimentation alone. The logger is very helpful about communicating when an option needs to be enabled and why.

**esbuild is not designed for HMR.**

- HMR stands for hot module replacement, which means state changes are persisted between browser refreshes. This may be a dealbreaker for you, if you’ve grown to love HMR.
- Personally speaking, _I don’t love HMR_ because it makes reasoning about state more opaque. That being said, implementing fast-refresh with server-sent events or WebSockets is incredibly easy and fun with your own watch mode handler.

**esbuild is not necessarily ‘for everyone‘.**

- If you’ve read this far, experimenting with esbuild is probably for you. 😉 That being said, even if you’re not interested in esbuild, you’ve probably used it indirectly or will. Why? Because esbuild already powers [Snowpack](https://github.com/snowpackjs/snowpack), [Vite](https://github.com/vitejs/vite), [SvelteKit](https://github.com/sveltejs/kit), [Remix Run](https://remix.run), and more. There are hundreds if not thousands of tools by now that have or will implement esbuild as part of their build pipeline. Winter is coming.

### Conclusion

esbuild is one of those rare technologies that deserves your time and attention. It is already helping to reimagine our industry and I’m incredibly excited to bet on it. [It doesn’t feel like other tooling](https://dev.to/jaredcwhite/the-shocking-immaturity-of-javascript-c70) and is here to stay.

---

Links:

- [esbuild GitHub](https://github.com/evanw/esbuild)
- [esbuild documentation](https://esbuild.github.io)
- [My Twitter](https://twitter.com/username_ZAYDEK)
- [My GitHub](https://github.com/zaydek)
- [Evan’s Twitter](https://twitter.com/evanwallace)
- [Evan’s GitHub](https://github.com/evanw)