We have some Angular 14.x applications implemented as micro-frontends (mfs) using the lib @angular-architects/module-federation": "^14.3.0"
.
We have some local libs that should be shared as singleton among all micro-frontends.
- If we deploy the
shell
and all mfs at the same time all works fine - If only a subset of them is individually deployed, a new instance of the shared local lib (service) is created, resulting in
undefined
when a method is called as the initial data set is not available.
This is visible from the image below:
The shared service is not created as singleton across all mfes:
@Injectable({
providedIn: 'platform',
})
export class LoginService implements Resolve<LoginService> {
private userInfo: UserInfo;
private userInfoSubject = new ReplaySubject<void>();
private companyInfoSubject = new ReplaySubject<void>();
// When a mf is newly deployed, this method returns undefined,
// as a new instance of this service is created and not the shared one is used.
getUserInfo(): UserInfo {
return this.userInfo;
}
setUserInfo(userInfo: UserInfo): void {
this.userInfo = userInfo;
this.userInfoSubject.next();
this.userInfoSubject.complete();
}
resolve(): Observable<LoginService> {
return forkJoin([this.userInfoSubject, this.companyInfoSubject]).pipe(
take(1),
map(() => this),
);
}
}
Our shell webpack config file:
module.exports = withModuleFederationPlugin({
name: 'shell',
filename: 'shell.js',
sharedMappings: ['@frontend/mfe-shared'], <-- These are the shared local libs
exposes: {
'./Module': 'apps/shell/src/app/app.module.ts',
},
remotes: {
// Remotes are loaded as remote module in shell/app.routing file
},
shared: share({
'@angular/core': { singleton: true, strictVersion: true, requiredVersion: '14.2.12' },
'@angular/common': { singleton: true, strictVersion: true, requiredVersion: '14.2.12' }
});
The shell routes file:
const routes: Routes = [
{
path: 'dashboard',
loadChildren: () => loadRemoteModule('./mfedashboard/dashboard.js').then((m) => m.AppModule),
{
path: 'partner',
loadChildren: () => loadRemoteModule('./mfepartner/partner.js').then((m) => m.AppModule),
}
];
@NgModule({
imports: [
RouterModule.forRoot(routes, {
onSameUrlNavigation: 'reload',
relativeLinkResolution: 'legacy',
paramsInheritanceStrategy: 'always' }),
],
exports: [RouterModule],
})
export class AppRoutingModule {}