Skip to content

Plugin architecture with Webpack 5, NX 15 and Angular 14+ (Ivy and AOT)

Notifications You must be signed in to change notification settings

faileon/angular-module-federation

Folders and files

NameName
Last commit message
Last commit date

Latest commit

e4d6fc7 · Oct 31, 2022

History

8 Commits
Oct 28, 2022
Oct 31, 2022
Oct 31, 2022
Oct 28, 2022
Oct 28, 2022
Oct 28, 2022
Oct 28, 2022
Oct 28, 2022
Oct 28, 2022
Oct 31, 2022
Oct 28, 2022
Oct 28, 2022
Oct 28, 2022
Oct 30, 2022
Oct 30, 2022
Oct 30, 2022

Repository files navigation

Plugin Architektura s Webpack5, NX a Angular 14+ (Ivy + AOT)

Jak spustit:

  1. Vybuildit plugin a widget (mělo by být součástí gitu, lze přeskočit na krok 3.)
    1. npm run build:remotes
  2. přetáhnout obsah složky dist/apps do apps/shell/assets (v assets tedy bude složka plugins a widgets)
  3. spustit aplikaci pomocí: nx run shell:serve:production
  4. otevřít aplikaci

  1. Alternativně lze vše servnout s hot reloadem:
    1. npm run start:all
  2. otevřít aplikaci

Jak to funguje

  • Využívá Module Federation koncept webpacku
  • Pro správné načítání modulů je nutné, aby webpack věděl, kde se daný modul nachází - k tomu slouží funkce setRemoteDefinitions, která se aktuálně volá při bootstrapu shell aplikace v apps/shell/src/main.ts
    • Tento manifest lze ale nastavit kdykoliv, jediná podmínka je, aby se tak stalo ještě před tím, než se pokusíme naloadovat modul pomoci funkce loadRemoteModule
  • Každý plugin si ve svém souboru module-federation.config.js může nastavit své entry pointy pomocí atributu exposes. Může to být modul, komponenta, cesty pro ng-router...
  • Aktuálně se například v apps/shell/src/app/app.routes.ts stahuje modul pluginu calendar, který zaregistruje své cesty do ng-routeru.
    • Nyní jsem se nezabýval implementací pro správu pluginu, takže cesta calendar je hardcoded, není ovšem problém tyto cesty nastavit dynamicky, např. po fetchnuti z BE.
  • V aplikaci apps/shell/src/app/app.component.ts se take renderuji 2 komponenty - jedna z pluginu calendar a druha z widgetu, jež je standalone builditelna komponenta.
    • Opět je to zde mírně hardoced, ale analogicky jako s cestami calendar pluginu, není problém tyto informace nastavit dynamicky, např. po fetchnuti z BE.

Výhody

  • pro načtení pluginu se používá funkce z NX @nrwl/angular/mf/loadRemoteModule, která pod pokličkou používá webpack a jejich ModuleFederation plugin
    • heavy lifting tedy dělá NX, potažmo webpack
    • kompatibilní s NX incremental builds
  • Díky webpacku chunkování funguje rekurzivně - lazy loading tedy funguje kdekoliv, i v dynamicky načteném pluginu
  • Samostatné pluginy a widgety lze servnout, tím pádem je velmi jednoduchý jejich developement. Lze je take vybuildit a zazipovat pro účel pluginizace (inspirace názvu z deduplikace).
    • Možnost snadné implementace e2e testu na jednotlivé pluginy

Nevyhody

  • zatím jsem na nic neřešitelného nenarazil

NX's withModuleFederation

  • Opinionated wrapper na ModuleFederationPlugin webpacku
  • Výchozí sdílené dependencies jsou:
    • @angular/animations
    • @angular/common
    • npm packages (podle root package.json)
    • všechny @nrwl/workspace:library
    • dependencies co vyčte z projectGraphu, tzn. pokud naimportuju nejakou knihovnu z monorepa, sam ji prida do sharovanych dependencies. Zpravidla je to žádoucí chování, lze tomu ale zabránit v configu.

Verzování

  • své verze si každý plugin a appka udržují ve svém package.json
  • appka nebo plugin si v souboru module-federation.config.js mohou dale specifikovat, které verze jednotlivých pluginu potřebují, např.:
  {
  // ...
  additionalShared: [
    ['@ng-mfa/shared/data-access/random', {singleton: true, requiredVersion: '~1.0.0', strictVersion: true}]
  ]
}
  • Pokud dojde k neshodě smluvených verzí, upozorní nás webpack následujícím runtime errorem:
    • Unsatisfied version 2.0.0 from shell of shared singleton module @ng-mfa/shared/data-access/random (required >=1.0.0 <1.1.1)
  • requiredVersion lze specifikovat v několika formátech:
    • standardní formát s ~ nebo ^, např.:
      • ~1.0.0, nebo-li 1.0.x
      • ^1.0.0, nebo-li 1.x.x
    • rozsah, např.:
      • '>=1.0.0 <1.1.1', nebo-li verze od 1.0.0 (včetně) až 1.1.1 (vyjma)

Commands

  • nový plugin:
    • npx nx g @nrwl/angular:remote plugins/<PLUGIN_NAME>
  • nový widget jako standalone component:
    • npx nx g @nrwl/angular:remote widgets/<WIDGET_NAME> --standalone

Source codes

TODO:

  • verify lazy loading inside plugins works
  • exposing component from a plugin and loading it elsewhere (shell)
  • standalone components (widgets)
  • create shared lib with some state and verify it's shared in app and plugins
  • versioning and shared modules, conflicts, etc.
  • dynamically create routes (requires implementing plugin management with backend, omitted for now)
  • build and zip automatically (streamline the process - so we don't have to zip manually)
  • verify that errors in plugins don't crash shell app, if so, implement error catching (perhaps outside ng-zone?)

About

Plugin architecture with Webpack 5, NX 15 and Angular 14+ (Ivy and AOT)

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published