0

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:

enter image description here

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 {}
Francesco
  • 9,947
  • 7
  • 67
  • 110

0 Answers0