Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Micro Frontends with Angular & Module Federatio...

Micro Frontends with Angular & Module Federation – kariera codeweek 11/2022

Micro Frontends are here to stay and today we have solid APIs to use them — even in enterprise architectures.

Thanks to Webpack 5 and community projects, integration is easier than ever before. Module Federation offers clear and well-designed APIs to ship self-contained parts of an application suite as Micro Apps. Many features like runtime integration and shared dependencies are directly supported.

This talk will provide answers on how to implement a mature Micro Frontend architecture with Angular and will show concrete implementations to put this into practice.

Michael Egger-Zikes

November 18, 2022
Tweet

More Decks by Michael Egger-Zikes

Other Decks in Programming

Transcript

  1. Architecture: Micro Frontends Module Federation Synchronize Routers What this talk

    is about Single Version Multi Version Michael Egger-Zikes (@MikeZks)
  2. About Michael • Michael Egger-Zikes ANGULARarchitects.io • Trainings, Consultancy, Reviews

    • Conference Speaker • Focus on Angular Remote Workshops: Public & tailored to your company angulararchitects.io/angular-workshops Michael Egger-Zikes (@MikeZks)
  3. Build Monolith Michael Egger-Zikes (@MikeZks) Booking Boarding Shared Feature Feature

    Feature Feature Feature … … … … … … … … … Flight App
  4. Micro Frontends Michael Egger-Zikes (@MikeZks) Booking Boarding Shared Feature Feature

    Feature Feature Feature … … … … … … … … … Booking App Boarding App
  5. Option 1: One App per Domain Booking Boarding Shared Feature

    Feature Feature Feature Feature … … … … … … … … … Booking App Boarding App Monorepo
  6. Option 2: One Monorepo per Domain Booking Boarding Shared Feature

    Feature Feature Feature Feature … … … … … … … … … Booking App Boarding App Publish shared libs seperately via npm Repository 2 Repository 1 Repository n
  7. Idea Michael Egger-Zikes (@MikeZks) const Component = import('http://other-app/xyz') Does not

    work with webpack/ Angular CLI Even lazy parts must be known at compile time!
  8. Webpack 5 Module Federation Michael Egger-Zikes (@MikeZks) Shell (Host) Micro

    Frontend (Remote) // Maps Urls in // webpack config remotes: { mfe1: 'http://...' } // Expose files in // webpack config exposes: { Cmp: './my.cmp.ts' } import('mfe1/Cmp')
  9. How to Get the Micro Frontend's URL? Michael Egger-Zikes (@MikeZks)

    Shell (Host) Micro Frontend (Remote) remoteEntry.js <script src="…"></script>
  10. How to Share Libs? Michael Egger-Zikes (@MikeZks) Shell (Host) Micro

    Frontend (Remote) shared: { '@angular/core': { … } } shared: { '@angular/core': { … } }
  11. Configuring Singletons Michael Egger-Zikes (@MikeZks) shared: { 'my-lib': { singleton:

    true, strictVersion: true // Error instead of warning! } } 11.0 10.1
  12. Usage Michael Egger-Zikes (@MikeZks) • Generate Module Federation config •

    Adjust generated configuration • webpack.config.js • Restart Dev-Server ng add @angular-architects/module-federation --project shell --port 4200 --type dynamic-host ng serve shell
  13. Abstracting Differences b/w SPA Frameworks Michael Egger-Zikes (@MikeZks) Wrap them

    into Web Components Angular App (MFE) React App (MFE) Corse-grained Web Component
  14. Module Federation: Bootstrap App Michael Egger-Zikes (@MikeZks) const main =

    await import('other-app/main'); main.bootstrap();
  15. Module Federation: Bootstrap App Michael Egger-Zikes (@MikeZks) const main =

    await import('other-app/main'); main.bootstrap(); const rootElm = document.createElement('app-root') document.body.appendChild(rootElm);
  16. Module Federation: Bootstrap App Michael Egger-Zikes (@MikeZks) await import('other-app/main'); //

    Self-Bootstrapping const rootElm = document.createElement('app-root') document.body.appendChild(rootElm);
  17. Routing to Another SPA? Michael Egger-Zikes (@MikeZks) await import('other-app/main'); const

    rootElm = document.createElement('app-root') document.body.appendChild(rootElm); WrapperComponent
  18. Challenges Michael Egger-Zikes (@MikeZks) • Bundle Size • Multiple Routers

    • Bootstrapping several Angular instances • Share Platform-Object when same version is reused • Share ngZone
  19. Step #1: Expose MFE via Web Components Michael Egger-Zikes (@MikeZks)

    @NgModule({ imports: [BrowserModule], declarations: [AppComponent], bootstrap: [] }) export class AppModule { }
  20. Step #1: Expose MFE via Web Components Michael Egger-Zikes (@MikeZks)

    @NgModule({ imports: [BrowserModule], declarations: [AppComponent], bootstrap: [] }) export class AppModule { constructor(private injector: Injector) { } }
  21. Step #1: Expose MFE via Web Components Michael Egger-Zikes (@MikeZks)

    @NgModule({ imports: [BrowserModule], declarations: [AppComponent], bootstrap: [] }) export class AppModule { constructor(private injector: Injector) { } ngDoBootstrap() { const AngularAppRoot = createCustomElement( AppComponent, { injector: this.injector }); customElements.define('angular-element', AngularAppRoot); } }
  22. Step #1: Expose MFE via Web Components Michael Egger-Zikes (@MikeZks)

    <my-app></my-app> Result: Browser renders component w/o framework support
  23. Step #2: Expose MFE via Module Federation Michael Egger-Zikes (@MikeZks)

    // webpack.config.js in Micro Frontend plugins: [ new ModuleFederationPlugin({ name: 'angularApp', filename: 'remoteEntry.js', exposes: { './rootapp': './projects/mfe/src/bootstrap.ts', }, shared: { '@angular/core': { 'requiredVersion: auto' }, '@angular/common': { 'requiredVersion: auto' }, '@angular/router': { 'requiredVersion: auto' }, 'rxjs': { 'requiredVersion: auto' } } }) ]
  24. Step #3: Use Bootstrap Helper in MFE Michael Egger-Zikes (@MikeZks)

    // Bootstrapping in both, Shell and Micro Frontends bootstrap(AppModule, { production: environment.production, appType: 'microfrontend'; });
  25. Step #3: Use Bootstrap Helper in Shell Michael Egger-Zikes (@MikeZks)

    // Bootstrapping in both, Shell and Micro Frontends bootstrap(AppModule, { production: environment.production, appType: 'shell'; });
  26. Step #4: Make Shell to Route to MFE Michael Egger-Zikes

    (@MikeZks) { path: 'multi-version', component: WebComponentWrapper, data: { type: 'module', remoteEntry: 'https://[…]/remoteEntry.js', remoteName: 'angularApp', exposedModule: './rootapp', elementName: 'angular-element‘ } as WebComponentWrapperOptions }
  27. Routing facts • Several bootstrapped apps → different Router instances

    • Only one address bar → only one URL • Default behavior →URL gets overwritten w/o coordination • Sounds like chaos, right? Michael Egger-Zikes (@MikeZks)
  28. URL Composition • Single App URLs: • Use the concept

    of Angular’s named RouterOutlets → But with different Apps and multiple Routers https://www.angulararchitects.io/mfe-1/article/search https://www.angulararchitects.io/mfe-2/invoice/edit/8 https://www.angulararchitects.io/(mfe-1:article/search//mfe-2:invoice/edit/8) Michael Egger-Zikes (@MikeZks)
  29. Step #5: Synchronize Routers (beta) Michael Egger-Zikes (@MikeZks) @NgModule({ imports:

    [ BrowserModule, AppRoutingModule, MicroAppRoutingModule.forShell({ name: 'shell' }) ], … }) export class AppModule { }
  30. Step #5: Synchronize Routers (beta) Michael Egger-Zikes (@MikeZks) @NgModule({ imports:

    [ BrowserModule, AppRoutingModule, MicroAppRoutingModule.forMicroApp({ name: 'mfe' }) ], … }) export class AppModule { }
  31. ! • Define your architecture targets • Decide between •

    Build Monolith • MF Single Version • MF Multi Version • Decide whether you need to show more than one Micro App at one time Key takeaways
  32. [web] ANGULARarchitects.io [twitter] Michael Egger-Zikes (@MikeZks) [npm] @angular-architects/module-federation @angular-architects/module-federation-tools @angular-architects/microapp

    [repo] https://github.com/mikezks/mfe-monorepo Contact | Libs | Source Remote Workshops: Public & tailored to your company angulararchitects.io/angular-workshops