Micro frontends give developers a modern, more nimble approach to application maintenance—especially since Angular works so well for enterprise solutions. Take a look at how to use Angular elements in this post.
Angular is one of the best frameworks for building a beast of an application in the enterprise environment. While arguably one of the more complex frameworks to learn, Angular, which is backed by Google, can build a strong and stable enterprise-grade application with large teams in mind. However, we don’t want to load a giant JavaScript package all at once or we would suffer losses in performance, development and quality.
Enter Micro Frontends
As the name suggests, our frontend code can now harness the power of micro services, or at least emulate the design pattern. We have seen a transition in the last few years away from classes to functional components, and away from complex REST API or GraphQL to an RPC approach. The Remote Procedure Call is back in style, getting reinvented with new packages like tRPC, and useful once again in modern backend programming. Now we must find a way to break apart our frontend as well in order to maintain our applications with modern approaches.
Angular Micro Frontend Approaches
- Module Federation – Webpack 5 offers the ability to build your application to form a single application at runtime. However, unless you need specific advanced options, this can add much unneeded complexity to your life. As a person who maintained a larger Angular Application with Webpack, I know it can be a pain and overkill.
- Web Components – You can build out your custom components using Angular elements. It is relatively easy to do and will allow you to use it anywhere in any HTML application. This is what we are going to learn here.
Angular Elements
Example Project Setup
- For this example, make sure you install the VS Code Live Server extension. It makes testing the web component extremely simple. Just click install. You could, however, use any HTTP server you want.
- Create a new project. You don’t need routing and can use just plain CSS. If you want a more complex application later, you can add whatever you want.
ng new micro-frontend
- Install Angular elements:
npm i @angular/elements
- Edit your
app.component.html
to be something simple, like hello world:
<p>Hello from micro frontend component!</p>
- Edit your
app.module.ts
to importInjector
from@angular/core
, make the bootstrap array empty, and add the custom elementapp-micro-frontend
. Name it whatever you like, although the Angular convention starts withapp
. Yourapp.module.ts
should look like this:
import { Injector, NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { createCustomElement } from '@angular/elements';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule
],
providers: [],
bootstrap: []
})
export class AppModule {
constructor(private injector: Injector) { }
ngDoBootstrap() {
const element = createCustomElement(AppComponent, {
injector: this.injector
});
customElements.define('app-micro-frontend', element);
}
}
- Replace
app-root
with your new elementapp-micro-frontend
in yourindex.html
file in order to reflect your new element. It should look like this:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>MicroFrontend</title>
<base href="https://www.telerik.com/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="https://www.telerik.comfavicon.ico">
</head>
<body>
<app-micro-frontend></app-micro-frontend>
</body>
</html>
Optional
- You may want to test your project first with
ng serve
, which should work with the newly created element. - If you’re reading this from the future when Zoneless Signals are ready (hopefully Angular 17+), then you will want to
get better performance in reactivity by opting out of Zone.js. Edit your
main.ts
file to add thenoop
argument like so:
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
platformBrowserDynamic().bootstrapModule(AppModule, { ngZone: 'noop' })
.catch(err => console.error(err));
- Add a bundle command to your
package.json
file under scripts. Unfortunately, Angular does not have an option to make sure there is only one JS file when building.
ng build -c production
will build the production version of your app.-prod
was depreciated and no longer works.--output-hashing=none
is also necessary so the separate JS files do not have a long hash added to their name.cat ./dist/ANGULAR_PROJECT_NAME/*.js > ./dist/ANGULAR_PROJECT_NAME/app-micro-frontend.js
– This will allow you to concatenate all the production JS files into one large JS file calledapp-micro-frontend.js
. However,cat
may not be available on your machine by default. Windows has thetype
command and PowerShell hasget-content
, etc. To keep this working across all devices, I decided to use bash withcat
. I don’t want to create a whole new script when a command should suffice here.
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"watch": "ng build --watch --configuration development",
"test": "ng test",
"bundle": "ng build -c production --output-hashing=none && bash -c \"cat ./dist/micro-frontend/*.js > ./dist/micro-frontend/app-micro.js\""
},
Run
npm run bundle
to bundle your application.Go to the
./dist/micro-frontend
folder and edit theindex.html
file. Replace the three script import tag files:runtime.js
,pollyfills.js
, andmain.js
withapp-micro.js
:
<!doctype html>
<html lang="en" data-critters-container>
<head>
<meta charset="utf-8">
<title>MicroFrontend</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
<link rel="stylesheet" href="styles.css"></head>
<body>
<app-micro-frontend></app-micro-frontend>
<script src="app-micro-frontend.js" type="module"></script>
</body>
</html>
- Edit the base path to work correctly with your
live-server
extension. You may not need to do this if you use another server for testing.
<base href="/dist/micro-frontend/">
- Right-click the
./dist/micro-frontend/index.html
file and click “Open with Live Server.” You should now see the final web component:
Hello from micro frontend component!
See my Angular Elements Repository for a working example.
Conclusion
Separating your Angular files into micro frontends can be a great way to simplify your life. It may not be for everyone, as sharing packages, standard lazy-loading techniques, and Git techniques could be an easier approach. There are also some challenges
when it comes to sharing state across these apps—you must track window
events, etc.
Nevertheless, using Angular elements can make this extremely easy, and could allow one team member to write a component in React, while another uses Vue. It is important to know about, and definitely useful for many large project teams.