Telerik blogs

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

  1. 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.
  2. 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

  1. 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.
  2. 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
  1. Install Angular elements:
npm i @angular/elements
  1. Edit your app.component.html to be something simple, like hello world:
<p>Hello from micro frontend component!</p>
  1. Edit your app.module.ts to import Injector from @angular/core, make the bootstrap array empty, and add the custom element app-micro-frontend. Name it whatever you like, although the Angular convention starts with app. Your app.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);
  }
}
  1. Replace app-root with your new element app-micro-frontend in your index.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="/">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" type="image/x-icon" href="favicon.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 the noop 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));
  1. 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 called app-micro-frontend.js. However, cat may not be available on your machine by default. Windows has the type command and PowerShell has get-content, etc. To keep this working across all devices, I decided to use bash with cat. 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\""
  },
  1. Run npm run bundle to bundle your application.

  2. Go to the ./dist/micro-frontend folder and edit the index.html file. Replace the three script import tag files: runtime.js, pollyfills.js, and main.js with app-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>
  1. 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/">
  1. 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.


About the Author

Jonathan Gamble

Jonathan Gamble has been an avid web programmer for more than 20 years. He has been building web applications as a hobby since he was 16 years old, and he received a post-bachelor’s in Computer Science from Oregon State. His real passions are language learning and playing rock piano, but he never gets away from coding. Read more from him at https://code.build/.

 

 

Related Posts

Comments

Comments are disabled in preview mode.