This tutorial is an extension for the @angular-architects/module-federation
tutorial here and shows, how to use the add-on lib @angular-architects/module-federation-tools
to load web components exposed via module federation.
Please find the upstream tutorial this tutorial extends here.
If you don't want to do the upstream tutorial first, you can use this example (see main branch) as the starting point.
-
Install
@angular-architects/module-federation-tools
:npm i @angular-architects/module-federation-tools
-
Restart your VS Code (or your TS Server within VS Code at least)
-
Open your shell's
app.routes.ts
and add the following routes:[...] // Add this import: import { WebComponentWrapper, WebComponentWrapperOptions, startsWith } from '@angular-architects/module-federation-tools'; [...] export const APP_ROUTES: Routes = [ [...] // Add these routes: { path: 'react', component: WebComponentWrapper, data: { type: 'script', remoteEntry: 'https://witty-wave-0a695f710.azurestaticapps.net/remoteEntry.js', remoteName: 'react', exposedModule: './web-components', elementName: 'react-element' } as WebComponentWrapperOptions }, { path: 'angular1', component: WebComponentWrapper, data: { type: 'script', remoteEntry: 'https://nice-grass-018f7d910.azurestaticapps.net/remoteEntry.js', remoteName: 'angular1', exposedModule: './web-components', elementName: 'angular1-element' } as WebComponentWrapperOptions }, { path: 'angular2', component: WebComponentWrapper, data: { type: 'script', remoteEntry: 'https://gray-pond-030798810.azurestaticapps.net//remoteEntry.js', remoteName: 'angular2', exposedModule: './web-components', elementName: 'angular2-element' } as WebComponentWrapperOptions }, { matcher: startsWith('angular3'), component: WebComponentWrapper, data: { type: 'script', remoteEntry: 'https://gray-river-0b8c23a10.azurestaticapps.net/remoteEntry.js', remoteName: 'angular3', exposedModule: './web-components', elementName: 'angular3-element' } as WebComponentWrapperOptions }, { path: 'vue', component: WebComponentWrapper, data: { type: 'script', remoteEntry: 'https://mango-field-0d0778c10.azurestaticapps.net/remoteEntry.js', remoteName: 'vue', exposedModule: './web-components', elementName: 'vue-element' } as WebComponentWrapperOptions }, { path: 'angularjs', component: WebComponentWrapper, data: { type: 'script', remoteEntry: 'https://calm-mud-0a3ee4a10.azurestaticapps.net/remoteEntry.js', remoteName: 'angularjs', exposedModule: './web-components', elementName: 'angularjs-element' } as WebComponentWrapperOptions }, { matcher: startsWith('angular3'), component: WebComponentWrapper, data: { type: 'script', remoteEntry: 'https://gray-river-0b8c23a10.azurestaticapps.net/remoteEntry.js', remoteName: 'angular3', exposedModule: './web-components', elementName: 'angular3-element' } as WebComponentWrapperOptions }, // THIS needs to be the last route!!! { path: '**', component: NotFoundComponent } ];
Remarks: The URL matcher
startsWith
makes the shell to ignore the remaining part of the URL. This is necessary when the loaded micro frontend uses a router too.Remarks: Please note that we are using
type: 'script'
here. This is needed for classic webpack setups as normally used in the Vue and React world as well as for Angular before version 13. Beginning with version 13, the CLI emits EcmaScript module instead of "plain old" JavaScript files. Hence, when loading a remote compiled with Angular 13 or higher, you need to settype
tomodule
. In our case, however, the remotes we find at the shown URLs in the cloud are Angular 12-based, hence we needtype: 'script'
. -
Open your shell's
app.component.html
and add the following links:<!-- Add these links --> <li><a routerLink="/react">React</a></li> <li><a routerLink="/angular1">Angular 1</a></li> <li><a routerLink="/angular2">Angular 2</a></li> <li><a routerLink="/angular3/a">Angular 3</a></li> <li><a routerLink="/vue">Vue</a></li> <li><a routerLink="/angularjs">AngularJS</a></li>
-
Open your shell's
bootstrap.ts
and use thebootstrap
helper function found in@angular-architects/module-federation-tools
for bootstrapping:import { AppModule } from './app/app.module'; import { environment } from './environments/environment'; import { bootstrap } from '@angular-architects/module-federation-tools'; bootstrap(AppModule, { production: environment.production, appType: 'shell', });
Remarks: This special bootstrap function takes care of some workarounds necessary to run several versions of Angular side by side.
-
Start your
shell
and themfe1
project (e. g. by callingnpm run run:all
) and try it out.
In this part of the lab, we will investigate the loaded micro frontend that has been called "MF Angular #3" before. We want to draw your attention to the following details:
-
The application is bootstrapped with the bootstrap function already used above. Please note that here,
appType
is set tomicrofrontend
. -
The
AppModule
is wrapping some components as web components using Angular Elements in it's ngDoBootstrap method. -
The webpack config exposes the whole
bootstrap.ts
file. Hence, everyone importing it can use the provided web components. -
The webpack config shares libraries like
@angular/core
.
If you would like to know more about Module Federation with Angular take a look at this article series about Module Federation.