How to build angular cli application with esbuild

Are you curious if it's possible to build ng-cli generate application with esbuild - 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:

and code generated with ng-cli:

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

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:

$ 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:

"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:

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:

declare module "*.html" {
  const content: string;
  export default content;
}

With those changes in place, we can already see the build passing:

$ npm run esbuild                   

> [email protected] 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:

<!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:

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

Links

Summary

You can find the whole codebase in this repository:

GitHub logo marcin-wosinek / esbuild-ng-cli

Proof of a concept for esbuild script for ng cli generated project

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.

40