How to build angular cli application with esbuild
Tags: esbuild, angular
Published: 2021-07-10 15:00:29

Are you curious if it's possible to build ng-cli generate application with [esbuild](http://esbuild.github.io/) - js bundling tool that is gaining popularity because of it very fast speed? It is, at least with a simplify proof-of-a-concept app; and with a bit of tweaking to the code.

# Starting point

My starting point is esbuild command shown & discussed in:
{% post marcinwosinek/how-to-build-minimal-angular-12-app-with-esbuild-54cc %}

and code generated with ng-cli:

```sh
$ npx -p @angular/cli ng new esbuild-ng-cli
```

{% asciinema 424838 %}

probably due to some recent package updates, I needed to tweak dependencies before the installation passed.

# esbuild install & configuration

We need few more steps to build with esbuild. First, installing esbuild as dependency:
```sh
$ npm install esbuild --save-dev

added 1 package (...)
```

Then we need build script. As we are not yet doing complete migration to esbuild, I'll leave `npm run build` as it was created - on webpack, and add dedicated `esbuild` script:

```sh
"esbuild": "esbuild src/main.ts --bundle --outfile=dist/main.js --loader:.html=text --minify"
```

There are few things included in this command:
* `src/main.ts` - is the script entry point - from there esbuild start finding all dependecies
* `--bundle` - tell esbuild to bundle all files into one bundle file
* `--outfile=dist/main.js` - the target of our build
* `--loader:.html=text` - makes HTML files interpreted as strings. It's similar to `raw-loader` in webpack
* `--minify` - minimize our code. It's not as effective as angular main configuration, but it's much better than leaving code unoptimized.

The necessary tweaks to the code, is to replace `src/app/app.component.ts` with:
```ts
import { Component } from '@angular/core';

import template from './app.component.html';

@Component({
  selector: 'app-root',
  template,
  // styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'esbuild-ng-cli';
}
```

`templateUrl` is replace by explicit template load, and css import I dropped to simplify the proof-of-a-concept application.

For the TS complication to accept the HTML import, we need to add `index.d.ts` with:
```ts
declare module "*.html" {
  const content: string;
  export default content;
}
```

With those changes in place, we can already see the build passing:
```sh
$ npm run esbuild                   

> esbuild-ng-cli@0.0.0 esbuild
> esbuild src/main.ts --bundle --outfile=dist/main.js --loader:.html=text --minify


  dist/main.js  761.1kb

⚡ Done in 124ms
```

The speed is impressive - less than 1 second. Unfortunately the bundle size is much bigger than one produce by native setup - 170.87kB, but build time almost 13s.

Note that the esbuild specific changes brake the standard webpack build - we would need some tweaks to have those two coexists without troubles.

# HTML file

For quick testing the app, we will use quick & dirty html; inspired by the webpack output. The `./index.html`:

```html
<!DOCTYPE html><html lang="en"><head>
  <meta charset="utf-8">
  <title>EsbuildNgCli</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
<body>
  <app-root></app-root>
<script src="dist/main.js"></script>
</body></html>
```

if we visit our page now, it will fail with:
```
Error: In this configuration Angular requires Zone.js
```

in the browser console. We can address it by adding one line to `./src/main.ts`:
```ts
import 'zone.js';

import { enableProdMode } from '@angular/core';
/** the rest of the file **/
```

this increases the bundle size to `798.2kb`

# The working application

The final app works the same as with the original build:
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2277dfnq1ik6xbzejukm.png)

# Links
* [my course about esbuild](https://bit.ly/esbuild-course)
* You can see the working example at:
https://marcin-wosinek.github.io/esbuild-ng-cli/

# Summary

You can find the whole codebase in this repository:
{% github marcin-wosinek/esbuild-ng-cli no-readme %}

This topic could be expanded in multiple ways
* more real work application
* adding css support
* setting up dev server with esbuild
* real esbuild & webpack coexistence - maybe it makes sense to have quick dev & heavily optimized production build 
* schematics for generating esbuild-friendly code immediately with ng-cli
* some other code generators set up with esbuild

let me know in the comments if those or any other extension are interesting for you.