# Azure Functions + esbuild = 😍🤯

I first discovered `esbuild` as a builder for Angular in [this Reddit post](https://www.reddit.com/r/Angular2/comments/s60cro/50x_faster_builds_with_esbuild_production_build/). I was amazed! Seeing this, I thought: "There must be other ways to utilize this!"

## What is `esbuild`?

[`esbuild`](https://esbuild.github.io/) calls itself "An extremely fast JavaScript bundler". I can definitely confirm that! And the main reason for that is, that it's written in Go - unlike our ol' reliable `tsc`. Also, it's plugin API makes it extremely flexible. Did I mention that it also has native TypeScript support?

## What advantages does this bring?

- **Reduced bundle size:** `esbuild` has two features that enable this - bundling and code-splitting. These features allow us to compile all external dependencies (from our *node_modules* folder) into the final bundle. Because `esbuild` can also minify the bundle, this decreases bundle size drastically
- **Reduced build time**: Like I mentioned before - `esbuild` is extremely fast. Combined with a watch mode this makes for crazy fast development speed. Build time for my Function App with 28 Functions: 800ms 🤯 Now, this is only half the truth. `esbuild` doesn't do type checking so we have to run `tsc --noEmit` at least in our CI pipeline (which isn't quite as fast unfortunately).

## How do I build Azure Functions with it?

Great question! Here's how you can do it:

First, install `esbuild` using npm: `npm i -D esbuild`

Then, create a build script in the root of the project:

```js
// build.mjs -> .mjs so we can use TLA (Top-level-await)

import { build } from 'esbuild';

await build({
  entryPoints: ['my-func/index.ts'],
  format: 'esm',
  splitting: true,
  minify: true,
  bundle: true,
  platform: 'node',
  target: 'node12'
  sourcemap: false,
  watch: false,
  outdir: 'dist',
  outExtension: { '.js' : '.mjs' }
});
```

Now, simply adjust the `scriptFile` property in every `function.json` to account for the new file extension and you're good to go. 

Or are you? 🧐 While writing this article, I fell into some traps and rabbitholes. Like for example:

- `__dirname` and `__filename` not being available in ESM
- `esbuild` not being able to convert CJS requires to ESM imports
- The output directory not being correct when there is only one Azure Function

## What now?

These pitfalls and rabbitholes caused me to develop a tool that catches all of those and allows for easy extension of the `esbuild` config that I think is a good default. You can also either use it from the CLI or via code (which I would recommend).

Let's have a look:

First, install it in your project using npm: `npm i -D esbuild-azure-functions`.

Then, create a build script in the root of the project:

```js
// build.mjs -> .mjs so we can use TLA (Top-level-await)

import { build, BuilderConfigType } from 'esbuild-azure-functions';

const config: BuilderConfigType = {
  project: process.cwd(),
  esbuildOptions: {
    outdir: 'myoutdir'
  }
};

await build(config);
```

And that's the basic config. By default, the tool looks for every `index.ts` file in the `project` directory. For a more detailed documentation, checkout the GitHub repo below!

## Benchmark

To wrap it up, here are some of the number I've observed

### Bundle size

Bundle size decreased massively. Most of that probably comes from the fact that we don't just throw the `node_modules` folder into the app package.

Now, I've included zip file sizes for both Linux and Windows. I run my Node.js Azure Functions on Windows and Windows produces a zip file that's quite a lot smaller than one created on Linux.

![Bundle size chart](https://cdn.hashnode.com/res/hashnode/image/upload/v1645357129993/nDwDp_jgI.png)

### Build time

As mentioned above, build time is very fast.

![az-func-esbuild_speed-chart.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1645357189405/iqDblQHkI.png)

%[https://github.com/beyerleinf/esbuild-azure-functions]

I hope you liked this blog post! If you have any questions, feel free to hit me up!

Cheers!

*[Wanna buy me a coffee?](https://www.buymeacoffee.com/beyerleinf)*
