A libary to enable the usage of the router module within Angular projects defining custom elements
npm install angular-elements-routerThe angular elements router is a libary for using the Angular Router within Angular Elements.
- Lazy loading — The bundle is loaded when the route of the micro frontend is activated.
- Non-intrusive — Use only the features you need, easy opt-out once Angular starts supporting the router in Angular Elements out of the box.
- No dependencies — Besides Angular this library does not include any dependencies.
```
$ npm install --save angular-elements-router
You have an Angular application that acts as a platform and an Angular application that acts as a micro frontend.
A build of the micro frontend results in a single build that registers custom elements on loading.
To be able to reference your custom element in the routes, you need to create a host component.
You can use the aerRouting on the custom element to pass route changes to the micro frontend and to allow the micro frontend to pass route changes to the platform.
`typescript
import { Component } from "@angular/core";
@Component({
selector: "app-host",
template: ,`
})
export class MicroFrontendHostComponent {}
To lazy load your custom element, you need to create a host module in the platform.
Import AngularElementsRouterModule to be able to use the aerRouting directive.CUSTOM_ELEMENTS_SCHEMA
Use the schema to make Angular accept the custom element in the host component.**
Use the path to pass all sub paths to the custom element.
`typescript
import { AngularElementsRouterModule } from "angular-elements-router";
import { MicroFrontendHostComponent } from "./micro-frontend-host.component";
const routes: Routes = [
{
path: "**",
component: MicroFrontendHostComponent,
},
];
@NgModule({
declarations: [MicroFrontendHostComponent],
imports: [RouterModule.forChild(routes), AngularElementsRouterModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class MicroFrontendHostModule {}
`
Choose a route under which your micro frontend should be loaded.
Use the LoadBundleGuard to load the bundle of your micro frontend on the first activation of the route.
`typescript
import { LoadBundleGuard } from "angular-elements-router";
const routes: Routes = [
{
path: "micro-frontend",
canActivate: [LoadBundleGuard],
data: {
bundleUrl: "http://localhost:4201/main.js",
},
loadChildren: () =>
import("./micro-frontend-host/micro-frontend-host.module").then(
(m) => m.MicroFrontendHostModule
),
},
];
`
Use the EntryRoutingService in the Angular component representing the custom element.
This way, route changes are passed to the Angular router in the micro frontend and in the other direction to the platform.
`typescript
import { EntryRoutingService } from 'angular-elements-router';
@Component({
selector: 'mf-angular-entry',
template: ,
})
export class EntryComponent implements OnChanges, OnDestroy {
@Input() route?: string;
@Output() routeChange = new EventEmitter
route$ = new Subject
private destroyed$ = new Subject
constructor(private entryRoutingService: EntryRoutingService) {
this.entryRoutingService.registerRouting(this.routeChange, this.route$, this.destroyed$);
}
ngOnDestroy() {
this.destroyed$.next();
}
ngOnChanges() {
this.route$.next(this.route);
}
`
The module in your micro frontend needs to define the custom element in the browser on bootstrap of the module.
`typescript
import { EntryComponent } from "./entry.component";
import { createCustomElement } from "@angular/elements";
@NgModule({
declarations: [EntryComponent],
imports: [BrowserModule],
providers: [],
})
export class AppModule {
constructor(private injector: Injector) {}
ngDoBootstrap() {
const customElement = createCustomElement(EntryComponent, {
injector: this.injector,
});
window.customElements.define("mf-entry", customElement);
}
}
`
To resolve the ambiguity of '/' within the micro frontend, you can reserve /root to reference the root of the platform and / to reference the root of the micro frontend.
This way, you can navigate to links outside of the micro frontend from within the micro frontend.
`typescript
import { NoComponent } from "angular-elements-router";
const routes: Routes = [
{ path: "root", children: [{ path: "**", component: NoComponent }] },
...otherRoutes,
];
`
By default, the Angular router within the micro frontend tries to update the browser url.
Use the NoopLocationStrategy to prevent this, such that the platform has the only access.
`typescript
import { NoopLocationStrategy } from "angular-elements-router";
@NgModule({
imports: [RouterModule.forRoot(routes)],
providers: [{ provide: LocationStrategy, useClass: NoopLocationStrategy }],
exports: [RouterModule],
})
export class AppRoutingModule {}
`
For the independent development of the micro frontend, a minimal dev platform consisting of an index.html with some Javascript can be of advantage.
This dev platform can be used both locally and also be deployed and used together with the bundle.
To use it, include the dev-platform.js in the scripts of your micro frontend in the angular.json.
`json`
{
"build": {
"builder": "ngx-build-plus:build",
"options": {
"singleBundle": true,
"outputHashing": "none",
...,
"scripts": [
"node_modules/angular-elements-router/src/dev-platform.js"
]
},
}
Setup an index.html in the micro frontend app.
`html``