Table of Contents Show
Micro frontends are a software architecture pattern in which a single web application is composed of multiple small and independent frontend applications, known as “micro frontends.”
Each micro frontend is owned by a separate team and is responsible for a specific part of the overall user interface. The different micro frontends are integrated into a single web application by using techniques such as iframes, web components, or dynamic JavaScript imports.
The goal of using micro frontends is to allow different teams to work independently on their own micro frontends and to integrate their work into the main application without affecting the other teams’ work.
This can help to improve the scalability, maintainability, and evolvability of the overall web application.
There are several approaches to implementing micro frontends, and the specific approach used will depend on the requirements and constraints of the project.
Some common considerations when implementing micro frontends include how to handle routing, how to share data between micro frontends, and how to handle authentication and authorization.
Micro frontends in Angular
In Angular, micro frontends can be implemented by using a combination of different techniques, such as lazy loading, the Angular Router, and the Angular CDK’s Portal module.
One approach to implementing micro frontends in Angular is to create a main shell application that is responsible for bootstrapping the Angular application and loading the different micro frontends as lazy-loaded modules.
The micro frontends can be implemented as separate Angular libraries that are packaged and deployed independently of the main shell application.
The Angular Router can be used to handle routing between the different micro frontends and the main shell application.
The Router allows the main shell application to define routes that correspond to the different micro frontends, and it can lazy-load the micro frontends when the routes are activated.
The Angular CDK’s Portal module can be used to create a “portal” in the main shell application that the different micro frontends can use to render their content.
The micro frontends can use the Angular CDK’s DomPortalOutlet directive to render their content into the portal in the main shell application.
By using these techniques, it is possible to implement micro frontends in Angular in a way that allows different teams to work independently on their own micro frontends and to integrate their work into the main application without affecting the other teams’ work.
Kent Wynn
Angular CDK’s DomPortalOutlet directive
The Angular CDK’s DomPortalOutlet directive is a part of the Angular CDK (Component Development Kit) that allows you to render a component or a template outside the Angular application context.
It is typically used to render a component or template into a “portal” that is created in the main application shell.
To use the DomPortalOutlet directive, you first need to create a portal outlet in the main application shell by using the Angular CDK’s DomPortalOutlet directive.
This creates an element in the main application shell that the micro frontends can use to render their content.
Next, you can create a micro frontend that uses the Angular CDK’s DomPortalOutlet directive to render its content into the portal outlet in the main application shell.
The micro frontend can pass the content it wants to render (such as a component or a template) to the DomPortalOutlet directive, and the directive will take care of rendering the content into the portal outlet.
Here is an example of how to use the DomPortalOutlet directive to create a portal outlet in the main application shell and render a component into the portal:
<!-- main application shell template -->
<ng-template cdkPortalOutlet></ng-template>
// micro frontend component
@Component({
selector: 'micro-frontend',
template: '<p>Micro frontend content</p>'
})
export class MicroFrontendComponent {
constructor(private portalOutlet: DomPortalOutlet) {}
ngOnInit() {
this.portalOutlet.attach(new ComponentPortal(MicroFrontendComponent));
}
}
In this example, the main application shell template contains a cdkPortalOutlet
directive that creates a portal outlet.
The MicroFrontendComponent
uses the DomPortalOutlet
directive to attach itself to the portal outlet, causing its template to be rendered into the portal outlet in the main application shell.
Using DomPortalOutlet – Real Practice
Here is a more complete example of how to use the Angular CDK’s DomPortalOutlet directive to create a main application shell with a micro frontend.
In this example, we have a main application shell that displays a header and a footer, and a micro frontend that displays some content in the middle.
The micro frontend is implemented as a separate Angular library and is lazy-loaded by the main application shell.
// main application module
import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';
import { DomPortalOutlet, PortalModule } from '@angular/cdk/portal';
import { AppComponent } from './app.component';
import { AppHeaderComponent } from './app-header/app-header.component';
import { AppFooterComponent } from './app-footer/app-footer.component';
@NgModule({
declarations: [AppComponent, AppHeaderComponent, AppFooterComponent],
imports: [
RouterModule.forRoot([
{
path: 'micro-frontend',
loadChildren: () => import('micro-frontend').then(m => m.MicroFrontendModule),
},
]),
PortalModule,
],
bootstrap: [AppComponent],
})
export class AppModule {}
// main application component
import { Component, ViewChild, AfterViewInit } from '@angular/core';
import { DomPortalOutlet } from '@angular/cdk/portal';
@Component({
selector: 'app-root',
template: `
<app-header></app-header>
<ng-template cdkPortalOutlet></ng-template>
<app-footer></app-footer>
`,
styles: [],
})
export class AppComponent implements AfterViewInit {
@ViewChild(DomPortalOutlet) portalOutlet: DomPortalOutlet;
ngAfterViewInit() {
this.portalOutlet.attach(new ComponentPortal(MicroFrontendComponent));
}
}
// micro frontend module
import { NgModule } from '@angular/core';
import { MicroFrontendComponent } from './micro-frontend.component';
@NgModule({
declarations: [MicroFrontendComponent],
imports: [],
exports: [MicroFrontendComponent],
})
export class MicroFrontendModule {}
// micro frontend component
import { Component } from '@angular/core';
@Component({
selector: 'micro-frontend',
template: '<p>Micro frontend content</p>',
styles: [],
})
export class MicroFrontendComponent {}
In this example, the main application module defines a route for the micro frontend, which is lazy-loaded by the main application shell when the route is activated.
The main application component contains a cdkPortalOutlet
directive that creates a portal outlet, and the ngAfterViewInit
lifecycle hook is used to attach the MicroFrontendComponent
to the portal outlet, causing its template to be rendered into the portal outlet in the main application shell.
Angular CDK’s DomPortalOutlet vs Nx Monorepo
The Angular CDK’s DomPortalOutlet directive is a part of the Angular CDK (Component Development Kit) that allows you to render a component or a template outside the Angular application context.
It is typically used to render a component or template into a “portal” that is created in the main application shell.
Nx is a set of tools and libraries for building scalable, enterprise-grade Angular applications. It provides a set of best practices and patterns for building modular, scalable, and maintainable Angular applications.
One way to use Nx to build micro frontends is to create a monorepo using the Nx workspace, and to define each micro frontend as a separate Angular library in the workspace.
The main application shell can then import and use the different micro frontends as libraries, using techniques such as lazy loading and the Angular CDK’s DomPortalOutlet directive to integrate the micro frontends into the main application.
In this way, Nx can provide a powerful toolset for building and managing micro frontend architectures in Angular, while the Angular CDK’s DomPortalOutlet directive can be used to implement the actual rendering of the micro frontends into the main application shell.
Kent wynn
Use Nx to build micro frontends
To use Nx to build micro frontends, you can follow these steps:
- Create a new Nx workspace using the
npx create-nx-workspace
command. - Define each micro frontend as a separate Angular library in the workspace. You can use the
nx generate @nrwl/angular:library
command to generate a new library in the workspace. - Implement each micro frontend as a standalone Angular application, with its own components, templates, and styles.
- Configure the main application shell to import and use the different micro frontends as libraries. You can do this by lazy-loading the micro frontend libraries using the Angular Router, or by using the Angular CDK’s DomPortalOutlet directive to render the micro frontends into a portal in the main application shell.
- Use Nx’s tools and libraries to build, test, and deploy the main application and the micro frontends. Nx provides a set of tools for managing the dependencies between the different libraries in the workspace, and for building and testing the application in a consistent and scalable way.
By following these steps, you can use Nx to build a scalable, modular, and maintainable architecture for your micro frontend application.
Lazy-loading the Nx micro frontend libraries using the Angular Router
To lazy-load micro frontend libraries using the Angular Router in an Nx workspace, you can follow these steps:
- Define a route for each micro frontend in the main application’s router configuration.
- Use the
loadChildren
property to specify the path to the micro frontend’s module file, and use theimport
function to lazy-load the micro frontend module.
Here is an example of how to define a route for a micro frontend in the main application’s router configuration:
const routes: Routes = [
{
path: 'micro-frontend',
loadChildren: () => import('@my-workspace/micro-frontend').then(m => m.MicroFrontendModule),
},
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule],
})
export class AppRoutingModule {}
In this example, the main application defines a route for the micro-frontend
path, and uses the loadChildren
property to specify the path to the MicroFrontendModule
in the micro-frontend
library.
When the micro-frontend
route is activated, the Angular Router will lazy-load the MicroFrontendModule
and its associated components, templates, and styles.
By using the Angular Router to lazy-load the micro frontend libraries, you can split your application into multiple independently-developed and deployed micro frontends, while still allowing the main application to navigate between the different micro frontends using the Router.
In conclusion
Micro frontends are a software architecture pattern in which a single web application is composed of multiple small and independent frontend applications, known as “micro frontends.”
Each micro frontend is owned by a separate team and is responsible for a specific part of the overall user interface. The different micro frontends are integrated into a single web application by using techniques such as iframes, web components, or dynamic JavaScript imports.
In Angular, micro frontends can be implemented using a combination of different techniques, such as lazy loading, the Angular Router, and the Angular CDK’s Portal module.
The Angular CDK’s DomPortalOutlet directive can be used to create a “portal” in the main application shell that the different micro frontends can use to render their content.
Nx can provide a powerful toolset for building and managing micro frontend architectures in Angular.
Using micro frontends can help to improve the scalability, maintainability, and evolvability of a web application by allowing different teams to work independently on their own micro frontends and to integrate their work into the main application without affecting the other teams’ work.
However, it is important to carefully consider the trade-offs and challenges of using micro frontends, such as the increased complexity of the overall application architecture and the need to carefully coordinate the integration of the different micro frontends.