Astro is a relatively new web framework that has a focus on helping you build faster websites. It also has a very interesting extension point in that you can bring your own UI framework of choice, including React, Svelte, Vue, and more. I even rewrote my Angular blog to use Astro in its alpha release days. This post is about bringing things full circle and using Angular components inside an Astro project.
TL;DR
GitHub repo: https://github.com/brandonroberts/angular-astro-islands
Sample website: https://angular-analog-astro-islands.netlify.app/
Partnership Opportunities: https://analogjs.org/docs/sponsoring
I initially wanted to use Angular components in Astro but couldn't do to multiple constraints. Many things have changed since then. Angular v14 includes standalone components that no longer need NgModules. Astro has continued to be developed, switched from Snowpack to Vite for its underlying build tool, and been released as 1.0. In the meantime, I've been working on a Analog, a meta-framework for building Angular applications and websites powered by Vite.
Astro provides integrations to allow additional UI frameworks to render their components inside Astro projects. With these pieces together, we can now take Angular components, render them in Astro, and hydrate them on the client.
Let's dive in!
Creating a New Astro Project
First, create a new Astro project:
With npm:
npm init astro
With yarn:
yarn create astro
Follow the prompts, along with choosing Just the basics to start. Next, is adding the @analogjs/astro-angular
integration.
Adding the Angular Integration
The @analogjs/astro-angular
integration adds support for using Angular components in an Astro project. The integration provides the Vite Plugin for Angular to compile and transform Angular components, renders Angular components on the server, and hydrates the components as needed on the client.
Use the astro add
command to install the integration:
astro add @analogjs/astro-angular
This command:
- Installs the
@analogjs/astro-angular
package. - Adds the
@analogjs/astro-angular
integration to theastro.config.mjs
file. - Installs the necessary Angular dependencies to render Angular components on the server hydrate them on the client, and common Angular dependencies, such as
@angular/common
and@angular/forms
.
After installation, the astro.config.mjs
looks like this:
import { defineConfig } from 'astro/config';
import analogjsAngular from "@analogjs/astro-angular";
// https://astro.build/config
export default defineConfig({
integrations: [analogjsAngular()]
});
Setting up the TypeScript config
The Angular integration needs a tsconfig.app.json
at the root of the project for compilation.
Create a tsconfig.app.json
in the root of the project.
{
"extends": "./tsconfig.json",
"compileOnSave": false,
"compilerOptions": {
"baseUrl": "./",
"outDir": "./dist/out-tsc",
"forceConsistentCasingInFileNames": true,
"strict": true,
"noImplicitOverride": true,
"noPropertyAccessFromIndexSignature": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"sourceMap": true,
"declaration": false,
"downlevelIteration": true,
"experimentalDecorators": true,
"moduleResolution": "node",
"importHelpers": true,
"noEmit": false,
"target": "es2020",
"module": "es2020",
"lib": ["es2020", "dom"]
},
"angularCompilerOptions": {
"enableI18nLegacyMessageIdFormat": false,
"strictInjectionParameters": true,
"strictInputAccessModifiers": true,
"strictTemplates": true
},
"files": [],
"include": ["src/**/*.ts"]
}
You can tweak the compiler settings as needed.
Adding an Angular Component
The Angular integration only supports rendering standalone components. With that caveat out of the way, defining an Angular component using standalone features is relatively straightforward.
Define a component in the components folder. The example below uses src/components/hello.component.ts
.
import { NgIf } from '@angular/common';
import { Component } from '@angular/core';
@Component({
selector: 'app-hello',
standalone: true,
imports: [NgIf],
template: `
<p>Hello from Angular!!</p>
<button (click)="toggle()">Toggle</button>
<p *ngIf="show">Toggled</p>
`,
})
export class HelloComponent {
show = true;
toggle() {
this.show = !this.show;
}
}
This is a pretty simple Angular component that toggles some text to show change detection working properly.
Next, add the Angular component to the Astro component template. In the generated Astro project, add the HelloComponent to the src/pages/index.astro
page.
---
import Layout from '../layouts/Layout.astro';
import Card from '../components/Card.astro';
import { HelloComponent } from '../components/hello.component.ts';
---
<Layout title="Welcome to Astro.">
<main>
<h1>Welcome to <span class="text-gradient">Astro</span></h1>
<!-- Angular Component -->
<HelloComponent />
<!-- HTML 😉 -->
</main>
</Layout>
This only renders the HTML from the Angular component. To hydrate the component on the client, use one of Astro's client directives:
<HelloComponent client:visible />
Find more information about Client Directives in the Astro documentation.
Developing the Website
To view the running website, start the dev server using the Astro CLI:
yarn astro dev
Visit the website at http://localhost:3000, including the new Angular component 😎.
Now its your turn to make some tweaks and play around 😀.
To build for deployment:
yarn astro build
Summary
This integration opens the door for web developers to build faster websites using Astro with Angular components. The Analog project and Astro Integration is actively being developed, so if you'd like to contribute, join us on GitHub and Discord.
Learn More
- Visit the Analog Docs
- Follow the Analog project on Twitter
- Join me at ViteConf to learn more about "Vite, Meta-frameworks, and Angular".
So what do you think? Leave a ❤️ on the post, and leave a comment and let me know your thoughts.
Top comments (9)
Great work! Are there any plans to support Angular components events (@Output) in Astro?
Thanks! Astro does not support component events on the client-side, so
@Output
is not supported.docs.astro.build/en/core-concepts/...
This looks very promising! The combination of having a fast, statically built website with the possibility of implementing dynamic UI where needed is very compelling to me.
For this reason, astro was interesting to me before I knew that people were working on an angular integration.
And this post makes it even more interesting to me, because I am primarily an angular guy :P
I hope astro finds wide adaption. Even if it's only within the angular community. Because I feel like other communities already have decent solutions for fast, SSR websites within their frameworks ecosystem.
Having worked with angular universal and also scully.io in the past. I think we still have some ground to make up in this area.
Great work @brandontroberts!
The tsconfig.app.json was not recognised and I added it to the normal tsconfig.json.
The toggle button did not triggered change detection on my local following. Any idea why this may happen?my editor was hinting me to not use the .ts file extension during import. But this is obviously necessary in an astro file.
Looks really cool, especially in a time when SSR is so painfully large. After following your basic example, I noticed my common bundle is 313kb yet yours is only 95kb... how were you able to achieve a "production" build? I don't see it in the help etc
Hi this relay amazing! Is it possible to bring all the Angular feature into Astro. Like Angular reactive forms, Angular service injecting, Angular material components, etc.
Hi
do you know if it supports AngularJS (v1)?
Thanks
@brandontroberts great post.
anyway to force the Astro / Analog integration to client side only globally i.e
analogjsangular({ ssr: false})
Thanks Sergio.
This isn't possible, because the client-side control is handled by Astro and not the Analog integration. Astro is no client-side JavaScript by default, so you have to opt into it when using the components on the page.