Bridging Analog to Angular with esbuild and Vite

Bridging Analog to Angular with esbuild and Vite

It wasn’t long ago that Analog went 1.0 bringing a stable full-stack meta-framework to the Angular community. One of the biggest conversations around Analog is the SFC and if its only available in Analog applications. There’s good news, as this post covers how you can use Analog features in your existing Angular applications.

TL;DR GitHub Repo – https://github.com/brandonroberts/angular-esbuild-analog-example

If you’ve been outside of the Angular bubble and wondered how we got here, Josh Morony has a video on what started as the .ng file format for Angular, and how it evolved into the Analog SFC.

Customizing Esbuild in Angular Applications

Much has been said about Angular’s migration from Webpack to esbuild and Vite, dramatically improving build performance and developer experience. We can take this a step further with a custom esbuild builder that allows additional features including esbuild plugins, middleware, and HTML transformers.

The Angular Devkit exposes these APIs for library authors to build on top of what Angular handles out of the box. Jenia “JeB” Barabanov has been maintaining custom Angular builders for Webpack and Jest for a while already, and introduced a custom builder for esbuild and the Vite dev server.

You can check out his repo at: https://github.com/just-jeb/angular-builders

With this custom esbuild builder, it opens up the door to add a custom esbuild plugin to support the Analog SFC.

Adding the Analog SFC to an Angular application

With the custom esbuild builder, you have the option to try the Analog SFC in an Angular 17.1+ application.

Note: The Analog SFC is still experimental!

With that out of the way, let’s dive in!

First, you need to install the custom esbuild builder and Analog Vite plugin for Angular:

npm i -D @angular-builders/custom-esbuild @analogjs/vite-plugin-angular

Next, you need to update the angular.json builder for build to use the new builder.

For the application builder:

– “builder”: “@angular-devkit/build-angular:application”,
+ “builder”: “@angular-builders/custom-esbuild:application”,

For the dev-server builder:

– “builder”: “@angular-devkit/build-angular:dev-server”,
+ “builder”: “@angular-builders/custom-esbuild:dev-server”,

Next, create an esbuild directory in the root of the application with two files.

├── esbuild
│ ├── plugins.js
│ ├── package.json
└── angular.json

In the package.json, add { “type”: “module” } and save it.

In the plugins.js, add the esbuild plugin for the Analog SFC.

import { analogSFC } from @analogjs/vite-plugin-angular/esbuild;

export default [analogSFC()];

In the options for the application builder, add a plugins array that includes the path to the esbuild/plugins.js file.

“builder”: “@angular-builders/custom-esbuild:application”,
“options”: {
“outputPath”: “dist/angular-esbuild-analog-example”,
“scripts”: [],
“plugins”: [“./esbuild/plugins.js”]
},

Next, create an analog.d.ts in the src directory with some type information.

interface ImportAttributes {
analog: imports | providers | viewProviders | exposes;
}

declare global {
import type { Component } from @angular/core;

interface Window {
/**
* Define the metadata for the component.
* @param metadata
*/

defineMetadata: (
metadata: Omit<
Component,
| template
| standalone
| changeDetection
| styles
| outputs
| inputs
>
) => void;

/**
* Invoke the callback when the component is initialized.
*/

onInit: (initFn: () => void) => void;
/**
* Invoke the callback when the component is destroyed.
*/

onDestroy: (destroyFn: () => void) => void;
}
}

declare module *.analog {
import { Type } from @angular/core;

const cmp: Type<any>;
export default cmp;
}

Now comes the fun part!

Create a hello.analog file in the src folder with a component.

<script lang=“ts”>
// hello.analog
import { signal } from @angular/core;

const count = signal(0);

function add() {
count.set(count() + 1);
}
</script>

<template>
<h2>
Hello Angular from Analog SFC
</h2>

<p>
{{count()}}
</p>

<button (click)=“add()”>Increment</button>
</template>

<style>
h2 {
color: blue;
}
</style>

Lastly, in the app.routes.ts file, define a route that navigates to the Hello component. Analog SFCs can be used in combination with the Angular Router!

import { Routes } from @angular/router;
import Hello from ./hello.analog;

export const routes: Routes = [
{ path: , component: Hello }
];

Run ng serve and navigate to the application running locally.

Now ship to production! Just kidding 😉.

Analog SFCs are also interopable with Angular components, but must be enabled by the experimental-local compilationMode in the tsconfig.json

We’ve love for you to try out the SFC and give us your feedback. To find out more, check out the Analog SFC docs. Also join the community on Discord.

Using a custom esbuild builders opens up many possibilities to bring more Analog features to Angular applications. We’re excited to explore more opportunities in the future. If you’re also interested to learn more about how Analog and Vite work together with Angular, check out the Angular, Analog, and Vite post by Robin Goetz.

Join the Community 🥇

Visit and Star the GitHub Repo

Join the Discord

Follow us on Twitter

If you enjoyed this post, click the ❤️ so other people will see it. Follow AnalogJS and me on Twitter/X, and subscribe to my YouTube Channel for more content!

Leave a Reply

Your email address will not be published. Required fields are marked *