AngularAtlasAusg. 22.2

Kap. 13Architektur im großen Maßstab57 / 75

Micro Frontends

Wann es sich lohnt, eine App in mehrere Deployments aufzuteilen und wann es nur Komplexität ist: Native Federation, Module Federation, iframes, Web Components.

Architektur ~0 Min. Lesezeit

Ein Micro Frontend ist ein Stück UI, das ein Team unabhängig baut, testet und ausliefert und das dann mit den anderen zur Laufzeit im Browser zusammengesetzt wird. Das entscheidende Wort ist „unabhängig“: Wenn zwei Teile zusammen ausgeliefert werden müssen, sind sie keine Micro Frontends, sondern Module derselben Anwendung — egal, wie getrennt ihre Ordner sind.

Die Architektur löst ein organisatorisches Problem, kein technisches: mehrere autonome Teams, die in unterschiedlichem Rhythmus ausliefern wollen, ohne sich gegenseitig zu blockieren. Der Preis ist Komplexität zur Laufzeit: Versionen von Abhängigkeiten, Integrationsfehler, visuelle Konsistenz, Testing, Observability.

Kurz gesagt
  • Micro Frontends lösen ein organisatorisches Problem (Teams, die unabhängig ausliefern), kein technisches.
  • Der Preis ist real: mehr JavaScript, Abhängigkeitsversionen, die synchron bleiben müssen, schwierigere End-to-End-Tests.
  • Für Angular mit esbuild ist Native Federation die empfohlene Variante. Web Components und iframes passen, wenn du Frameworks mischst oder volle Isolation willst.
  • Die Verträge zwischen Apps (Routen, Events, Versionen) zählen mehr als die Technik. Jede entfernt geladene App braucht einen Fallback.
  • Mit nur einem Team ist ein Monorepo mit klaren Grenzen fast immer einfacher.
Warum das wichtig ist

Die meisten Angular-Anwendungen, auch große, sind mit einer einzigen Anwendung in einem Monorepo mit klaren Grenzen und Lazy Loading besser bedient. Micro Frontends sind die richtige Antwort für ein paar ganz bestimmte Situationen — und sonst eine teure Quelle von Problemen. Diese Seite hilft dir, beides zu unterscheiden und sie bei Bedarf mit Native Federation korrekt zu bauen.

Was es ist und was nicht

Ein Micro-Frontend-System hat drei Eigenschaften, alle drei sind Pflicht:

  • Separater Build — jeder Teil hat seine eigene Pipeline und seine eigene package.json (oder zumindest sein eigenes Build-Target).
  • Separates Deployment — das Catalog-Team veröffentlicht eine neue Version, ohne dass die Shell oder das Cart-Team etwas tun müssen.
  • Komposition zur Laufzeit — eine Shell (Host) erfährt erst im Browser, welche Version jedes Remotes sie laden soll, meist aus einem Manifest.
BUILD-TIME — KEIN Micro Frontend
  libs/catalog ─┐
  libs/cart    ─┼─► ng build shell ─► ein einziges Deployment
  libs/reviews ─┘
  eine Version, ein Release, Verträge vom Compiler geprüft

RUNTIME — Micro Frontends
  catalog → build → deploy → catalog…/remoteEntry.json ─┐
  cart    → build → deploy → cart…/remoteEntry.json    ─┼─► die Shell komponiert sie
  reviews → build → deploy → reviews…/remoteEntry.json ─┘   im Browser
  N Versionen, N Releases, Verträge erst zur Laufzeit geprüft
KompositionSo funktioniert esIst es ein Micro Frontend?
Bibliotheken in einem Monorepodie Shell importiert libs/catalog; ein Build, ein Deploymentnein — es passiert zur Build-Zeit (siehe Monorepo)
Lazy Routes, @defergetrennte Chunks, aber vom selben Build erzeugtnein — dieselbe Anwendung
Native / Module FederationRemotes veröffentlichen ES-Module + Metadaten; die Shell lädt sie anhand des Manifests und teilt Abhängigkeitenja
Web Componentsjedes Team liefert ein Bundle aus, das Tags definiert; die Shell verwendet sie nurja (siehe Angular Elements)
iframesgetrennte Dokumente in einem Frameja — die stärkste Isolation

Echte Gründe, falsche Gründe

Die Gründe, die den Preis rechtfertigen, drehen sich fast alle um Menschen und Auslieferung:

  • Autonome Teams mit unterschiedlicher Taktung. Das Checkout-Team liefert mehrmals täglich aus, das Catalog-Team einmal pro Woche, und ein gemeinsames Release blockiert beide: Eine Regression im Katalog stoppt einen dringenden Payment-Fix.
  • Sehr große Organisationen. Dutzende Frontend-Entwickler am selben Produkt, mehrere Fachdomänen, jede mit klarer Verantwortung (Conways Gesetz: Die Architektur bildet am Ende ohnehin die Organisation ab).
  • Schrittweise Migration (Strangler Fig). Eine neue Shell „umhüllt“ die alte Anwendung (AngularJS, ein älteres Angular, ein anderes Framework); Screens werden einer nach dem anderen migriert, und der alte Code schrumpft, bis er verschwindet — ohne einen „Big-Bang“-Rewrite.
  • Getrennte Produkte unter einer Erfahrung: Übernahmen, Geschäftsbereiche, Portale, die bestehende Anwendungen zusammenführen.

Falsche Gründe klingen in Präsentationen gut, haben aber günstigere Lösungen:

„Wir wollen MFE für …“Warum das nicht trägtWas das Problem tatsächlich löst
Skalierbarkeit / PerformanceMFE fügt beim Start Bytes, Requests und Versionsverhandlung hinzuLazy Routes, @defer, SSR, Optimierungen
sauberer, modularer CodeModularität ist eine Eigenschaft des Codes, nicht des DeploymentsBibliotheken + Import-Regeln (Grenzen, Struktur)
schnellere BuildsN Pipelines bedeuten N Stellen, die kaputtgehen könneninkrementeller Build und Cache (Nx affected) in einem Monorepo
jedes Team wählt sein eigenes Frameworktechnologische Vielfalt ist ein dauerhafter Kostenfaktor: ein doppeltes Design-System, Leute, die sich kaum zwischen Teams verschieben lassennur akzeptieren, wenn es unvermeidbar ist (Migration, Übernahme)
Der einfache Test

Wenn du keine zwei Teams nennen kannst, die sich heute beim Release gegenseitig blockieren, hast du das Problem nicht, das Micro Frontends lösen.

Der Preis

Jeder der folgenden Kosten taucht in der Praxis auf; der Unterschied zwischen einem gesunden und einem fragilen System ist, ob du von Anfang an einen Plan dafür hast.

KostenWas konkret passiertWie du sie im Griff behältst
Geteilte Versionenein Remote, das mit einem anderen Angular gebaut wurde, kann die Runtime der Shell nicht nutzen; Major-Upgrades müssen koordiniert werdenüberall dieselbe Version, ein gemeinsamer Upgrade-Kalender, eine Prüfung in der CI
Integration zur Laufzeitein umbenannter Export in einem Remote bricht die Shell in Produktion, nicht beim KompilierenExposes wie eine öffentliche API behandeln (semver), Contract-Tests, ein Fallback pro Remote
Doppelte Bundleswas nicht geteilt wird, wird N-mal heruntergeladen; was geteilt wird, wird separat gebaut und ist daher nicht mehr pro Anwendung per Tree-Shaking bereinigtein Bundle-Analyzer, nur teilen, was sinnvoll ist
Design-Systemfünf Teams, fünf Versionen von Buttonsdas Design-System als geteiltes Paket + CSS-Tokens, verantwortet von einem Plattform-Team
Routingwem gehört die URL, was passiert bei einem direkten Deep Link in ein Remotedie Shell besitzt die Top-Level-Routen, jedes Remote exportiert Routes für sein Präfix
Auth und Sessiondas Token muss alle Remotes erreichen, der Refresh darf nur einmal stattfindenein HttpOnly-Cookie oder ein Auth-Service aus einer geteilten Bibliothek als Singleton (Auth-Refresh)
E2E-Testingjedes Team ist isoliert grün, der Bug tritt in der Komposition aufE2E auf „Shell + die Produktionsversionen der anderen“
Observability„Fehler in Produktion“ — aus welchem Remote, in welcher Version?die Version jedes Remotes in jedem Log, Source Maps pro Remote
Lokale Entwicklungdu startest fünf Server, um an einem zu arbeitenein Manifest pro Umgebung: die lokale Shell lädt die deployten Remotes, du startest nur, was du änderst

Native Federation Schritt für Schritt

Native Federation setzt das Module-Federation-Modell auf Webstandards um: Remotes sind gewöhnliche ES-Module, verbunden über eine Import Map. Für Angular 22 ist das Paket @angular-architects/native-federation 22.x — die Version folgt dem Angular-Major.Minor — und es bleibt beim esbuild-Builder der CLI (@angular/build:application), den es umhüllt. Das Projekt ist in die Organisation github.com/native-federation umgezogen. Der Mechanismus, Schritt für Schritt:

  1. Build. Jedes Remote erzeugt ES-Module und eine remoteEntry.json: was es exponiert (./routes → die erzeugte Datei) und welche Abhängigkeiten es teilt, mit version, requiredVersion, singleton, strictVersion.
  2. Start der Shell. main.ts ruft initFederation() vor Angular auf: Es liest das Manifest (Name → URL), lädt die Metadaten jedes Remotes, verhandelt die Versionen und schreibt die Import Map (mit es-module-shims).
  3. Bootstrap. Erst dann startet import('./bootstrap') Angular. Deshalb verschiebt das Schematic das Bootstrap in eine eigene Datei: @angular/core muss über die Import Map aufgelöst werden, also muss sie zuerst existieren.
  4. Navigation. loadRemoteModule('catalog', './routes') ist im Kern ein dynamisches import() einer URL auf dem Server des Catalog-Teams. Wenn der Code des Remotes import '@angular/core' ausführt, leitet die Import Map ihn zur Kopie der Shell: ein Angular, ein Root-Injector.
# die Version des Adapters folgt dem Angular-Major.Minor (22.2.x für Angular 22.2)
npm i -D @angular-architects/native-federation

ng g @angular-architects/native-federation:init \
  --project catalog --port 4201 --type remote
ng g @angular-architects/native-federation:init \
  --project shell --port 4200 --type dynamic-host

# Was das Schematic ändert:
#  • build/serve → @angular-architects/native-federation:build,
#    das an @angular/build:application (esbuild) delegiert
#  • main.ts → initFederation(...), danach import('./bootstrap');
#    das alte Bootstrap landet in bootstrap.ts
#  • erzeugt federation.config.mjs (+ public/federation.manifest.json beim dynamic-host)
#  • fügt es-module-shims zu den Polyfills hinzu (Import Maps mit Scopes)
#  • mit --webcomponent: Bootstrap als Custom Element (createApplication + define)
// catalog/federation.config.mjs — ein Remote, so wie 22.x es erzeugt
import {
  withNativeFederation,
  fromPackageJson,
} from '@angular-architects/native-federation/config';

export default withNativeFederation({
  name: 'catalog',

  exposes: {
    // die öffentliche API des Remotes
    './routes': './projects/catalog/src/app/catalog.routes.ts',
  },

  shared: fromPackageJson({
    singleton: true,
    strictVersion: true,
    requiredVersion: 'auto',
    build: 'package',
  })
    // ganz @angular/core, inklusive der Secondary Entry Points → eine einzige Kopie
    .patch(['@angular/core'], { includeSecondaries: { keepAll: true } }),

  skip: ['rxjs/ajax', 'rxjs/fetch', 'rxjs/testing', 'rxjs/webSocket'],

  features: { denseChunking: true },
});
// shell/src/main.ts — läuft VOR Angular:
// liest das Manifest, lädt die remoteEntry.json-Dateien, verhandelt die Versionen,
// schreibt die Import Map — erst dann wird bootstrap.ts (und @angular/core) geladen
import { initFederation } from '@angular-architects/native-federation';

initFederation('federation.manifest.json')
  .then((nf) => import('./bootstrap').then((m) => m.bootstrap(nf)))
  .catch((err) => console.error(err));
Was sich in 22.x geändert hat
  • Für Angular 22 kehrt Native Federation v4 in das Hauptpaket @angular-architects/native-federation zurück (für Angular 20–21 gab es die -v4-Bridge).
  • Das Schematic erzeugt federation.config.mjs mit fromPackageJson(...); shareAll und share bleiben verfügbar.
  • loadRemoteModule, direkt aus dem Paket importiert, ist als @deprecated markiert: Nutze die Variante aus dem Ergebnis von initFederation(), wie in app.routes.ts.
// Die Kurzform aus älteren Tutorials gibt es in 22.x noch,
// sie ist aber als @deprecated markiert:
import { loadRemoteModule } from '@angular-architects/native-federation';

const route = {
  path: 'catalog',
  loadChildren: () =>
    loadRemoteModule('catalog', './routes').then((m) => m.CATALOG_ROUTES),
};

// Der Grund, laut d.ts: Sie hängt von einer globalen Instanz und vom LETZTEN initFederation ab,
// ist also in Tests und mit mehreren Hosts fragil.
// Empfohlen: loadRemoteModule aus dem Ergebnis von initFederation (siehe app.routes.ts).

Die Demo unten bildet genau diesen Ablauf nach. Die Server sind simuliert, aber jedes „Remote“ ist eine echte Angular-Komponente, liegt in einem eigenen Chunk und wird mit einem dynamischen import() geladen — derselbe Mechanismus, den loadRemoteModule darunter verwendet. Catalog und Cart sprechen nur über Events auf window miteinander; die Reviews sprechen mit niemandem.

LiveShell + drei Remotes (Simulation, mit echtem Lazy Loading)
federation.manifest.json (editierbar)
Deployments (simulierte Server)
catalog.atlas.example
cart.atlas.example
reviews.atlas.example
shell@angular/core 22.2.2Warenkorb: —
<slot catalog>idle
<slot cart>idle
<slot reviews>idle
Was die Shell macht
Setze Reviews auf „offline“, setze Cart auf @angular/core 21.2.4 oder zerstöre eine URL im Manifest und drücke dann „Seite laden“: Jeder Slot scheitert für sich, mit Fallback und „Wiederholen“. „langsam (4 s)“ überschreitet das Timeout der Shell. Füge etwas aus dem Katalog hinzu: Das Badge der Shell aktualisiert sich über ein Event. In den DevTools → Network siehst du die echten Chunks der Remotes.

Geteilte Abhängigkeiten und Versionen

Für jedes Paket in shared deklariert ein Remote vier Dinge: version (womit es gebaut wurde), requiredVersion (was es akzeptiert; 'auto' = der Bereich aus der package.json, zum Beispiel ^22.2.0), singleton (eine einzige Instanz für alle) und strictVersion (lehnt eine Version außerhalb des Bereichs ab).

Warum Angular ein Singleton sein muss. @angular/core ist keine Bibliothek aus reinen Funktionen: Es ist die Runtime, die rendert, der Injector, die Change Detection. Kompilierte Templates rufen die Runtime-Instruktionen des Builds auf, mit dem sie kompiliert wurden, daher kann eine Komponente aus einer Kopie nicht von einer anderen gerendert werden. Selbst bei einer gewöhnlichen Bibliothek bedeuten zwei Kopien zwei verschiedene Klassen: inject(AuthService) im Remote fragt ein anderes Token an als das, das die Shell registriert hat, und dein „Singleton“ hat plötzlich zwei Instanzen.

Was passiert, wenn die Versionen nicht zusammenpassen, hängt vom Tool ab:

Situation (singleton: true)Native Federation (Orchestrator v4)Module Federation (webpack)
die geteilte Version erfüllt requiredVersiondas Remote nutzt die geteilte Kopie; die Version des Hosts hat Vorrangnutzt das Singleton
erfüllt sie nicht, strictVersion: truedas Remote bekommt eine eigene Kopie, in den scopes der Import MapFehler beim Laden: Unsatisfied version … of shared singleton module …
erfüllt sie nicht, strictVersion: falsenutzt trotzdem die geteilte Version + eine Warnungnutzt das Singleton + console.warn

Bei Angular rettet „eine eigene Kopie“ die Lage nicht: Das Remote hätte eine andere Runtime, seine Komponenten können also nicht in den Baum der Shell eintreten. Ein Remote mit einem anderen Major wird nur isoliert eingebunden — als Web Component mit eigenem Bootstrap oder in einem iframe. Wenn du es lieber beim Start als bei der Navigation herausfinden willst, hat der Orchestrator die Option strict.strictExternalCompatibility, die bei der Initialisierung einen Fehler wirft, statt Scopes anzulegen.

// Drei Wege, `shared` in federation.config.mjs zu schreiben

// 1. der Standard in 22.x: alles aus den dependencies der package.json, dieselben Regeln
shared: fromPackageJson({ singleton: true, strictVersion: true, requiredVersion: 'auto' }),

// 2. der klassische Stil (wird weiterhin exportiert)
shared: { ...shareAll({ singleton: true, strictVersion: true, requiredVersion: 'auto' }) },

// 3. explizit, Paket für Paket
shared: share({
  '@angular/core': { singleton: true, strictVersion: true, requiredVersion: 'auto' },
  // hat Zustand → Singleton
  '@ngrx/signals': { singleton: true, strictVersion: true, requiredVersion: 'auto' },
  // zustandsloses Hilfspaket: jedes Remote darf seine eigene Kopie haben
  'date-fns': { singleton: false },
}),

// requiredVersion: 'auto' → der Bereich aus der package.json (z. B. "^22.2.0")
// autoShareScope({ level: 'minor' }) → teilt nur zwischen Remotes
//   auf derselben Versionslinie (z. B. "ng22.2")
LiveVersionsverhandlung und die Import Map (Simulation)

Die Shell (Host) stellt @angular/core in Version 22.2.2 bereit, die im globalen Scope Vorrang hat.

Remotegebaut mitrequiredVersionsingletonstrictVersion
catalog
cart
reviews
catalogshare
22.2.2 erfüllt ^22.2.2 → nutzt die Kopie der Shell und lädt nichts zusätzlich herunter.
cartscope
22.2.2 erfüllt ~22.1.4 nicht; mit strictVersion bekommt es seine eigene Kopie 22.1.4, sichtbar nur in seinem Scope. Zwei Angular-Runtimes: Seine Komponenten lassen sich nicht im Baum der Shell rendern — binde es isoliert ein (Web Component mit eigenem Bootstrap).
reviewsskip + warning
22.2.2 erfüllt ^21.2.4 nicht, aber strictVersion: false → nutzt trotzdem 22.2.2, mit einer Warnung in der Konsole. Es kann funktionieren oder zur Laufzeit abstürzen — du erfährst es in Produktion.
Kopien von @angular/core heruntergeladen: 2eine zusätzliche Angular-Runtime
generierte Import Map
{
  "imports": {
    "@angular/core": "https://shell.example/core-22.2.2.js"
  },
  "scopes": {
    "https://cart.example/": {
      "@angular/core": "https://cart.example/core-22.1.4.js"
    }
  }
}
Simuliert die Regeln des Native-Federation-Resolvers für @angular/core. Ändere Version, Bereich und Flags jedes Remotes und verfolge das Urteil und die Import Map. Beachte, wie ~ (akzeptiert nur Patches) ohne echten Grund eine zusätzliche Kopie erzeugt und wie singleton: false immer ein zweites Angular erzeugt.
  • Ideal: dieselbe exakte Angular-Version in der Shell und in allen Remotes. ^ gibt dir Toleranz zwischen Minor-Versionen, aber AOT-kompilierter Code nutzt interne Runtime-Instruktionen — teste die Kombination, verlass dich nicht auf semver.
  • Der Host gewinnt, daher kann die Shell bei einer neuen Minor-Version vorangehen, solange die Bereiche der Remotes sie akzeptieren. Ein neues Major erfordert ein synchronisiertes Upgrade oder die Isolation des Remotes, das zurückgefallen ist.
  • Singleton + strictVersion für das Framework und für alles mit Zustand: Angular, Router, Stores, Design-System, die Auth-Bibliothek. Zustandslose Hilfspakete dürfen Nicht-Singletons bleiben.
  • autoShareScope() bindet das Teilen an eine Versionslinie (zum Beispiel ng22.2), damit du nicht versehentlich inkompatible Builds mischst.

Module Federation, Web Components, iframes

Module Federation (webpack)

@angular-architects/module-federation hat eine Version für Angular 22, aber es ist die „klassische“ Variante auf webpack: ng add stellt das Projekt vom esbuild-Builder auf @angular-builders/custom-webpack um (ab Angular 22; bis 21 nutzte es ngx-build-plus) und warnt ausdrücklich, dass für neue Projekte die Alternative Native Federation ist. Es gibt außerdem einen rspack-Builder, der als experimentell markiert ist. Wähle es nur, wenn du ein bestehendes Module-Federation-System erweiterst oder die Runtime mit Remotes teilen musst, die bereits auf webpack gebaut sind.

// Klassisches Module Federation (webpack) — @angular-architects/module-federation 22.x
const {
  shareAll,
  withModuleFederationPlugin,
} = require('@angular-architects/module-federation/webpack');

module.exports = withModuleFederationPlugin({
  name: 'catalog',
  exposes: {
    './routes': './projects/catalog/src/app/catalog.routes.ts',
  },
  shared: {
    ...shareAll({ singleton: true, strictVersion: true, requiredVersion: 'auto' }),
  },
});

Web Components

Jedes Remote startet mit createApplication() seine eigene Anwendung und definiert ein Tag; die Shell setzt es nur auf die Seite. Es funktioniert über verschiedene Angular-Majors und über Frameworks hinweg, weil nichts geteilt wird. Genau das ist sein Preis: Jedes Bundle bringt seine eigene Runtime mit (≈ 33 kB übertragen für ein einfaches Element, gemessen auf der Angular-Elements-Seite), es gibt kein gemeinsames DI, und die Kommunikation läuft über Attribute und Events. Es lässt sich gut mit Federation kombinieren: Ein Remote auf einem anderen Major wird als Web Component exponiert und trotzdem über loadRemoteModule geladen.

// Ein Remote auf einem ANDEREN Angular-Major (oder einem anderen Framework): isoliert eingebunden,
// als Web Component mit eigener Runtime.
//
// Remote — federation.config.mjs:  exposes: { './Bootstrap': './src/bootstrap.ts' }
// Remote — bootstrap.ts:
//   createApplication(appConfig).then(({ injector }) =>
//     customElements.define('mfe-legacy', createCustomElement(App, { injector })));
//
// Shell — eine Seite, die das Bundle lädt (sein Effekt: define) und dann das Tag verwendet
import { CUSTOM_ELEMENTS_SCHEMA, Component, inject, input, resource } from '@angular/core';
import { NATIVE_FEDERATION } from '../app.config';

@Component({
  selector: 'app-legacy-page',
  schemas: [CUSTOM_ELEMENTS_SCHEMA],
  template: `
    @if (bundle.hasValue()) {
      <mfe-legacy [attr.customer-id]="customerId()"></mfe-legacy>
    } @else if (bundle.error()) {
      <p role="alert">
        Das Legacy-Modul ist nicht verfügbar.
        <button (click)="bundle.reload()">Wiederholen</button>
      </p>
    }
  `,
})
export class LegacyPage {
  private readonly nf = inject(NATIVE_FEDERATION);
  readonly customerId = input.required<string>();

  protected readonly bundle = resource({
    loader: () => this.nf.loadRemoteModule('legacy', './Bootstrap'),
  });
}

iframes

Die stärkste Isolation: anderes Dokument, anderes JavaScript, anderes CSS; Fehler, Memory Leaks und Styles bleiben im Frame, und mit sandbox kannst du Code ausführen, dem du nicht vertraust. Du zahlst mit der Integration: Die Höhe wird über postMessage synchronisiert, ein Dialog kann den Frame nicht verlassen, Deep Links und Browser-Verlauf müssen von Hand verknüpft werden, Fokus und Barrierefreiheit werden kompliziert, und jeder Frame lädt die ganze Anwendung. Geeignet für Fremdcode, Legacy-Anwendungen, die du nicht ändern kannst, und interne Tools.

<!-- Die stärkste Isolation: anderes Dokument, anderes JS, anderes CSS;
     Fehler bleiben im Frame -->
<iframe
  src="https://billing.exemplu.ro/embed?customer=42"
  title="Abrechnung"
  sandbox="allow-scripts allow-same-origin allow-forms"
  loading="lazy"
  style="width: 100%; border: 0"
></iframe>

<!-- Der Preis: Die Höhe wird per postMessage übermittelt, ein Dialog kann den
     Frame nicht verlassen, Deep Links und Browser-Verlauf werden von Hand synchronisiert,
     und jeder Frame lädt die ganze Anwendung. -->

Verträge, Kommunikation, Fallback

Der Vertrag eines Remotes ist alles, was von außen von ihm abhängt: die Schlüssel in exposes, was sie exportieren, die Routenparameter, die sie lesen, die Events, die sie senden, und die geteilten Abhängigkeiten. Behandle ihn wie eine öffentliche API mit semver: Eine inkompatible Änderung bedeutet einen neuen Schlüssel (./routes-v2), und der alte bleibt, bis die Shell migriert ist.

Kommunikation, in der Reihenfolge, in der es sich lohnt, sie auszuprobieren:

  1. Die URL — Routenparameter und Query-Parameter. Kostenlos, verlinkbar, übersteht einen Refresh, und das Remote importiert nichts aus einem anderen Remote.
  2. Typisierte Events auf window, aus einem winzigen contracts-Paket (Typen + emit/listen). Vergiss nicht das Remote, das spät startet: Es muss den Zustand erfragen.
  3. Ein paar kleine Services, als Singletons geteilt — Auth, aktueller Benutzer, Feature-Flags — aus einer Bibliothek, die in shared enthalten ist.

Was du vermeiden solltest: einen gemeinsamen globalen Store (derselbe NgRx-Store oder derselbe Service, der den gesamten Zustand hält und von jedem Remote verwendet wird). Jede Änderung an der Form des Zustands wird zu einer koordinierten Änderung zwischen Teams — genau die Kopplung, die du entfernen wolltest. Jedes Remote behält seinen eigenen Zustand; zwischen ihnen reisen nur Events und URLs (siehe auch State Management).

// 1. Die URL ist der erste Kanal: kostenlos, verlinkbar, übersteht einen Refresh.
//    /catalog/audio?sort=price → das Remote liest aus der URL, nicht aus einem gemeinsamen Store.
//    (withComponentInputBinding() gehört in die SHELL: die Routen des Remotes
//    laufen im Router der Shell)
export class ProductList {
  readonly category = input<string>();                 // aus :category
  readonly sort = input<'price' | 'rating'>('rating'); // aus ?sort=
}

// 2. Auch die Navigation zwischen Remotes läuft über die URL:
//    das Remote importiert nichts aus einem anderen Remote.
this.router.navigate(['/cart'], { queryParams: { added: product.id } });

Fallback. Jedes Remote kann fehlen: ein fehlgeschlagenes Deployment, ein CDN, das ausgefallen ist, ein Fehler im Manifest einer Umgebung. Zwei Situationen, zwei Lösungen:

  • Eine ganze Route: Lass loadChildren scheitern und wandle den Fehler mit withNavigationErrorHandler in einen Redirect um. Ein abgelehnter Loader wird vom Router nicht gecacht, daher versucht die nächste Navigation das Remote erneut.
  • Ein Remote innerhalb einer Seite (ein Widget, ein Slot): Eine Shell-Komponente lädt das Remote mit resource, mit Timeout, Fallback und reload() für „Wiederholen“ — wie in der ersten Demo.
// Eine FEHLGESCHLAGENE Remote-ROUTE: lass loadChildren scheitern und leite um.
// Ein abgelehnter Loader wird vom Router NICHT gecacht → die nächste Navigation versucht es erneut.
import { ApplicationConfig, inject } from '@angular/core';
import {
  NavigationError,
  RedirectCommand,
  Router,
  provideRouter,
  withNavigationErrorHandler,
} from '@angular/router';
import type { NativeFederationResult } from '@angular-architects/native-federation';
import { routes } from './app.routes';

export const appConfig = (nf: NativeFederationResult): ApplicationConfig => ({
  providers: [
    provideRouter(
      routes(nf),
      withNavigationErrorHandler((e: NavigationError) => {
        const router = inject(Router);
        const target = `/indisponibil?url=${encodeURIComponent(e.url)}`;
        return new RedirectCommand(router.parseUrl(target));
      }),
    ),
  ],
});

// ✗ Die Falle: Ein Fallback, den der Loader zurückgibt, ist für den Router ein ERFOLG.
//   Er wird an der Route gecacht, bis die Seite neu lädt, sodass „Wiederholen“
//   das Remote nie wieder erreicht:
//   loadComponent: () => nf.loadRemoteModule(...).then(...).catch(() => RemoteDown)

Wann ja, wann nein

Die Entscheidung hängt mehr von der Organisation ab als vom Code. Der Score unten wendet die Regeln dieser Seite an: Er ist keine Zauberformel, zwingt dich aber, die Fragen zu beantworten, auf die es ankommt, und zeigt dir, warum eine Empfehlung zustande kommt.

LiveBrauchen wir Micro Frontends?
Reifegrad der Organisation
Sonderfälle
Du brauchst wahrscheinlich keine Micro Frontends: Monorepo + Lazy Routes.
Monorepo + Lazy Routes (eine Anwendung)85
  • + 3 Teams: Grenzen im Code (Bibliotheken, Import-Regeln) reichen meist aus
  • + ein gemeinsames Release ist akzeptabel
Native Federation (Angular-Remotes, geteilte Runtime)0
  • + ab ~4 Teams wird Autonomie wichtig
  • − ohne echten Bedarf an unabhängigem Deployment rechtfertigt MFE seinen Preis nicht
  • + dieselbe Angular-Version → @angular/core kann ein geteilter Singleton sein
  • − ohne Plattform, Pipelines pro Team und Monitoring landet die Komplexität von MFE in Produktion
Web Components (Angular Elements, Runtime pro Bundle)0
iframes (vollständige Isolation)0
Starte bei deiner echten Situation. Beachte, wie stark unabhängiges Deployment und der organisatorische Reifegrad wiegen, wie „mehrere Angular-Majors“ die Empfehlung in Richtung Web Components verschiebt und wie nicht vertrauenswürdiger Code einen iframe verlangt.
Micro Frontends
  • Mehrere autonome Teams (grob 4–5 oder mehr) am selben Produkt, mit unterschiedlicher Release-Taktung, die sich heute gegenseitig blockieren.
  • Unabhängiges Deployment ist Pflicht (vertraglich, regulatorisch, unterschiedliche Rhythmen) → Native Federation mit derselben Angular-Version.
  • Schrittweise Migration weg von einer alten Anwendung → eine neue Shell + Strangler Fig; alte Screens als Web Components oder iframes, bis sie verschwinden.
  • Getrennte Produkte unter derselben Marke, mit klarer Verantwortung pro Fachdomäne.
  • Du hast das Fundament bereits: ein Plattform-Team für die Shell und das Design-System, CI/CD pro Team, Monitoring nach Remote-Version.
Etwas anderes
  • Ein Team oder wenige Teams, die zusammen ausliefern können → eine Anwendung in einem Monorepo, mit Lazy Routes und Grenzen.
  • Das Problem ist Performance → @defer, Lazy Loading, SSR; MFE macht es schlimmer.
  • Das Problem ist verworrener Code → Bibliotheken, Import-Regeln, Architektur; MFE verschiebt das Gewirr nur zwischen Repositories.
  • Du willst nur Komponenten zwischen Anwendungen wiederverwenden → eine veröffentlichte Bibliothek oder eine, die im Monorepo geteilt wird.
  • Ein Widget für fremde Seiten → eine einzelne Web Component (Angular Elements), keine Architektur.
  • Es gibt niemanden, der die Shell besitzt, die Verträge und die gemeinsamen Upgrades → verschiebe es, bis es jemanden gibt.

Häufige Stolperfallen

  • Die „geteilte“ Bibliothek, die nicht in shared steht → jedes Remote bündelt sie separat, sodass providedIn: 'root' zwei Instanzen erzeugt (zwei Klassen, zwei Tokens). Nimm die Bibliotheken mit Zustand in shared auf und prüfe die remoteEntry.json.
  • singleton: false bei @angular/core oder ein Remote auf einem anderen Major → zwei Angular-Runtimes. Überall dieselbe Version; für Ausnahmen Isolation (Web Component, iframe).
  • strictVersion: false, damit es „durchgeht“ → die Meldung verschwindet aus der Konsole, das Problem bleibt und zeigt sich in Produktion. Repariere die Versionen, nicht das Flag.
  • Ein Fallback, der aus loadComponent zurückgegeben wird (.catch(() => RemoteDown)) → der Router cacht ihn an der Route bis zu einem Refresh, und „Wiederholen“ erreicht das Remote nie. Lass den Loader scheitern oder nutze eine Host-Komponente mit reload().
  • Kein Timeout → eine remoteEntry.json, die nicht antwortet, hält die Seite für immer im Zustand „loading“. Setze bei jedem Laden eines Remotes ein Timeout.
  • Ein Manifest für alle Umgebungen → Staging lädt die Produktions-Remotes (oder umgekehrt). Ein Manifest pro Umgebung, beim Deployment erzeugt.
  • Ein gemeinsamer globaler Store zwischen Remotes → Releases im Gleichschritt, ein verteilter Monolith. Lokaler Zustand + Events + URL.
  • Ein Remote, das Code direkt aus einem anderen Remote importiert → eine versteckte Abhängigkeit zwischen Deployments. Alles läuft über libs/contracts oder über die URL.
  • Absolute Routen, die in einem Remote geschrieben sind (/products/42) → sie brechen, wenn die Shell es unter einem anderen Präfix einhängt. Navigiere relativ zur aktiven Route.
  • Globales CSS aus Remotes → die Styles eines Teams zerstören die eines anderen. Keine globalen Styles in Remotes; CSS-Tokens aus dem Design-System; ShadowDom für Web Components.
  • Fehler ohne Kontext → du weißt nicht, welches Remote in welcher Version abgestürzt ist. Hänge Name und Version des Remotes an jeden gemeldeten Fehler (siehe Fehlerbehandlung).

Spickzettel

// REMOTE — federation.config.mjs
withNativeFederation({
  name: 'catalog',
  exposes: { './routes': './src/app/catalog.routes.ts' }, // öffentliche API, versioniert
  shared: fromPackageJson({ singleton: true, strictVersion: true, requiredVersion: 'auto' }),
});

// SHELL — public/federation.manifest.json (eine pro Umgebung: dev / staging / prod)
// { "catalog": "https://catalog.exemplu.ro/remoteEntry.json" }

// SHELL — main.ts
initFederation('federation.manifest.json')
  .then((nf) => import('./bootstrap').then((m) => m.bootstrap(nf)));

// SHELL — Routen
const catalog = {
  path: 'catalog',
  loadChildren: () =>
    nf.loadRemoteModule<{ CATALOG_ROUTES: Routes }>('catalog', './routes')
      .then((m) => m.CATALOG_ROUTES),
};

// VERSIONEN: überall dieselbe Angular-Version; der Host hat Vorrang.
//   inkompatibel + strictVersion    → eigene Kopie in scopes (NF)
//                                     "Unsatisfied version …" (webpack MF)
//   inkompatibel, ohne strictVersion → nutzt die geteilte Version + Warnung
// KOMMUNIKATION: URL → typisierte Events (libs/contracts) → kleine geteilte Services.
//   Keine gemeinsamen Stores.
// AUSFALL: Route → withNavigationErrorHandler + Redirect
//          Slot → Host-Komponente mit Timeout + resource.reload()
// ANDERER MAJOR / ANDERES FRAMEWORK → Web Component mit eigener Runtime oder iframe

Kap. 13 · 0 von 4 abgeschlossen

Lektion abgeschlossen?

Markiere sie, dann erscheint sie auf deiner Karte: im Inhaltsverzeichnis und auf der Startseite.

Wird automatisch markiert, sobald du die ganze Lektion gelesen hast.

  1. Micro Frontends
  2. Web Components mit Angular Elements
  3. Monorepo, Bibliotheken & Grenzen
  4. Hexagonale Architektur (Ports & Adapters)
Deine ganze Karte ansehen

Alle 75 Seiten · tippen zum Filtern

  • 01Was ist neu in Angular 21 & 22Alle wichtigen Änderungen in v21 und v22 in Kürze, mit Link zur Seite, die sie jeweils erklärt.Start
  • 01Deine erste App, Schritt für SchrittEine Leseliste, von einer leeren Komponente bis zur fertigen App — Signals, @for, Inputs und Outputs, ein Service und ein Formular, Schritt für Schritt.Start
  • 01Schnelle Entscheidungen„Wohin damit?“, „Signal oder Observable?“, „Shared oder Feature?“ — kurze Antworten auf Alltagsfragen.Start
  • 01Angular-Interviewfragen60 echte Interviewfragen für Junior, Mid und Senior, mit der passenden Antwort, der Nachfrage und den Warnsignalen. Dazu ein Probeinterview.Start
  • 02Standalone & BootstrapWie eine App ohne NgModule startet: bootstrapApplication, app.config.ts, imports in der Komponente.Moderne Grundlagen
  • 02Data Binding & EventsInterpolation, Property- und Attribut-Bindings, Events mit $event und Tastenfiltern und wie [( )] aufgebaut ist — was in das DOM geht und was zurückkommt.Moderne Grundlagen
  • 02Control Flow: @if, @for, @switchDie Block-Syntax, die *ngIf/*ngFor/ngSwitch ersetzt, mit track, @empty und Exhaustive Checks.Moderne Grundlagen
  • 02@let und die neuen Template-AusdrückeLokale Variablen mit @let, Arrow Functions, Spread, Regex, instanceof, Kommentare in Tags.Moderne Grundlagen
  • 02@defer — Lazy Loading in TemplatesSchwere Komponenten nur laden, wenn sie gebraucht werden: Trigger, Prefetch, Placeholder, Loading, Error.Moderne Grundlagen
  • 02Class- & Style-BindingsWarum [class.x] und [style.x] ngClass und ngStyle abgelöst haben (mit automatischer Migration ab v21).Moderne Grundlagen
  • 02Komponenten-Styles & Kapselung:host, die drei Kapselungsmodi, Theming mit CSS-Variablen und warum ::ng-deep der letzte Ausweg ist.Moderne Grundlagen
  • 02Pipes: wann und wiePure vs. Impure Pipes, eigene Pipes und wie du zwischen Pipe, computed() und Methode wählst.Moderne Grundlagen
  • 03signal() und computed()Die reaktiven Grundbausteine: beschreibbarer Zustand, abgeleiteter Zustand, Gleichheit, untracked und Regeln zur Immutability.Signals & Reaktivität
  • 03effect() — wann ja, wann neinMit Signals synchronisierte Seiteneffekte: localStorage, Logging, imperative APIs. Und ihre Stolperfallen.Signals & Reaktivität
  • 03linkedSignal() — editierbarer abgeleiteter ZustandEin Signal, das sich zurücksetzt, wenn sich seine Quelle ändert, das du aber auch manuell setzen kannst.Signals & Reaktivität
  • 03resource, rxResource, httpResourceAsynchrone Daten als Signals: status, value, error, reload, automatischer Abbruch. Stabil seit v22.Signals & Reaktivität
  • 03debounced() — verzögerte SignalsDie „Debounce“-Variante eines Signals, ohne RxJS. Perfekt für die Suche.Signals & Reaktivität
  • 03Listen: suchen, filtern, sortieren, blätternEine Kette von computed-Signals, die nur neu berechnet, was sich geändert hat — mit den Filtern in der URL, damit ein Link dieselbe Ansicht öffnet.Signals & Reaktivität
  • 03Observables von null anWas ein Observable ist, subscribe und unsubscribe, die Operatoren, die du jede Woche brauchst, cold vs. hot — und wann ein Signal reicht.Signals & Reaktivität
  • 03Signals ↔ RxJStoSignal, toObservable, takeUntilDestroyed, outputFromObservable — und wann RxJS weiterhin die richtige Wahl bleibt.Signals & Reaktivität
  • 04input() und output()Inputs als Signals (required, transform, alias) und typisierte Outputs. Daten nach unten, Events nach oben.Komponenten: Kommunikation
  • 04model() — Two-Way-BindingBanana-in-a-Box [( )] mit einer einzigen API. Wann du es nutzt und wann input + output besser ist.Komponenten: Kommunikation
  • 04viewChild & contentChildQueries als Signals: viewChild, viewChildren, contentChild, contentChildren, die Option read.Komponenten: Kommunikation
  • 04Lifecycle & DestroyRefWelche Hooks in der Signals-Ära noch zählen, afterNextRender, DestroyRef und typisiertes ngOnChanges.Komponenten: Kommunikation
  • 04Content Projectionng-content mit select, mehrere Slots, Standardinhalt und die Falle der bedingten Projektion.Komponenten: Kommunikation
  • 04ng-template & ngTemplateOutletTemplates als Werte: Render Props in Angular, typisierter Kontext und Anpassen von Komponenten.Komponenten: Kommunikation
  • 05Smart vs. DumbContainer vs. Presentational: wer den Zustand hält, wer nur anzeigt und wie du die beiden sauber trennst.Komponenten-Design
  • 05Generische Komponenten <T>Eine korrekt typisierte DataTable<T> oder Select<T>, mit Templates für Zellen.Komponenten-Design
  • 05Dynamische KomponentenNgComponentOutlet, createComponent mit inputBinding/outputBinding und ein Dashboard, das aus einer Konfiguration gebaut wird.Komponenten-Design
  • 05Direktiven & Host-KompositionAttribut-Direktiven, die host: {}-Metadaten und die Directive Composition API (hostDirectives).Komponenten-Design
  • 05Eigene Formular-ControlsFormValueControl (Signal Forms) vs. ControlValueAccessor: eine Sternebewertung, in beiden Varianten.Komponenten-Design
  • 05Change DetectionOnPush ist ab v22 der Standard, zone.js entfällt ab v21. Was das Rendering auslöst und wie du dir nicht die Finger verbrennst.Komponenten-Design
  • 06inject() & @Service()Der neue @Service()-Decorator ab v22, inject() vs. Konstruktor und der Injection-Kontext.Dependency Injection
  • 06Provider & die Injector-HierarchieRoot vs. Route vs. Komponente, useClass/useValue/useFactory/useExisting und die Modifier optional/self/skipSelf.Dependency Injection
  • 06InjectionToken & provideX()Typisierte Konfiguration, provideFeature()-Funktionen, makeEnvironmentProviders und Initializer.Dependency Injection
  • 06injectAsync() — Lazy ServicesLade einen schweren Service erst, wenn du ihn brauchst, mit Prefetch im Leerlauf.Dependency Injection
  • 07Ordnerstrukturcore / shared / features, was in welchen Ordner gehört und wie ein Feature von innen aussieht.Architektur der Anwendung
  • 07Shared vs. FeatureWann du eine Komponente nach Shared verschiebst und (vor allem) wann NICHT. Eine konkrete Checkliste.Architektur der Anwendung
  • 07Interfaces & ModelleInline-Interface oder eigene Datei? DTO vs. Domänenmodell, type vs. interface, wohin damit.Architektur der Anwendung
  • 07State Management mit SignalsEinfache Signal-Stores, Fassaden, lokaler vs. globaler Zustand und wann du NgRx brauchst.Architektur der Anwendung
  • 07Styleguide & NamensgebungDie aktuellen offiziellen Konventionen: Dateinamen ohne Suffixe, protected, readonly, Reihenfolge der Member.Architektur der Anwendung
  • 07Barrels, Aliase & Grenzenindex.ts, Pfad-Aliase, die öffentliche API eines Features und Abhängigkeitsregeln, die sich automatisch prüfen lassen.Architektur der Anwendung
  • 07Fehler: @boundary & ErrorHandlerDer neue @boundary-Block ab v22.2, der globale ErrorHandler, HTTP-Fehler und Fehler aus resource.Architektur der Anwendung
  • 08Modernes Routing & Lazy LoadingloadComponent, Child Routes, Parameter als Inputs und Parameter-Vererbung (neuer Standard in v22).Routing
  • 08Guards & ResolvercanActivate, canMatch, canDeactivate und resolve als Funktionen, mit Redirects über UrlTree / RedirectCommand.Routing
  • 09Signal Forms — die GrundlagenFormulare auf Basis von Signals: form(), [formField], schemabasierte Validierung. Stabil seit v22.Formulare
  • 09Signal Forms — fortgeschrittenEigene und feldübergreifende Validierung, async/HTTP mit Debounce, dynamische Listen, disabled/hidden, wiederverwendbare Schemas.Formulare
  • 09Typisierte Reactive FormsTypisierte FormGroup, nonNullable, FormArray — und wie sie neben Signal Forms bestehen.Formulare
  • 10HttpClient, Interceptors & die API-SchichtHttpClient ohne Setup (v21), Fetch als Standard (v22), funktionale Interceptors und eine API-Schicht mit DTO-Mapping.HTTP & Daten
  • 11Performance — eine ChecklisteWas wirklich zählt: OnPush + Signals, track, @defer, Lazy Routes, Bilder, Bundles und Hydration.Qualität & Performance
  • 11Testen mit VitestVitest ist ab v21 der Standard-Runner. TestBed, Komponenten mit Signals, Services, HTTP und Harnesses.Qualität & Performance
  • 11DevTools: ein Blick in deine AppChrome DevTools und Angular DevTools Schritt für Schritt: was jedes Panel zeigt, mit Übungen, die auf dieser Website funktionieren.Qualität & Performance
  • 11Angular AriaHeadless, barrierefreie Komponenten, die du nach Belieben stylst: Tabs, Accordion, Menü, Listbox...Qualität & Performance
  • 12SSR, Prerendering & Render ModesWann auf dem Server gerendert wird, wann beim Build und wann nur im Browser: RenderMode pro Route, app.routes.server.ts und die echten Kosten.SSR & Hydration
  • 12Hydration: Event Replay & inkrementellWie der Browser das Server-HTML übernimmt, ohne es neu zu rendern: vollständige Hydration, Event Replay, @defer (hydrate on …) und Mismatch-Fehler.SSR & Hydration
  • 12Servertauglicher Codewindow gibt es auf dem Server nicht: PLATFORM_ID, afterNextRender, DOCUMENT, TransferState, der HTTP-Cache und PendingTasks.SSR & Hydration
  • 13Micro FrontendsWann es sich lohnt, eine App in mehrere Deployments aufzuteilen und wann es nur Komplexität ist: Native Federation, Module Federation, iframes, Web Components.Architektur im großen Maßstab
  • 13Web Components mit Angular ElementscreateCustomElement: eine Angular-Komponente, die überall als HTML-Tag nutzbar ist, plus Kommunikation zwischen Apps über Events und BroadcastChannel.Architektur im großen Maßstab
  • 13Monorepo, Bibliotheken & GrenzenEin Workspace mit mehreren Apps und Bibliotheken: ng generate library, Nx, Secondary Entry Points, Publishing und Abhängigkeitsregeln.Architektur im großen Maßstab
  • 13Hexagonale Architektur (Ports & Adapters)Eine Domäne ohne Angular, Ports als abstrakte Klassen und austauschbare Adapter: HTTP, localStorage oder In-Memory, ohne die UI anzufassen.Architektur im großen Maßstab
  • 14Signals unter der HaubeDer reaktive Graph: Producer und Consumer, Push-Pull, warum computed lazy und glitch-frei ist, das Diamond-Problem und wann Effects laufen.Fortgeschrittene Reaktivität
  • 14Fortgeschrittenes RxJS: Operatoren höherer OrdnungswitchMap, mergeMap, concatMap und exhaustMap an einem Live-Diagramm, dazu Retry mit Backoff, shareReplay und wie du Leaks vermeidest.Fortgeschrittene Reaktivität
  • 14NgRx SignalStoreState Management im großen Stil auf Signals: withState, withComputed, withMethods, rxMethod, Entities und Hooks — und wann ein einfacher Store reicht.Fortgeschrittene Reaktivität
  • 14Zustandsautomaten mit SignalsKeine unmöglichen Zustände mehr: ein typisierter Automat auf Signals, mit Übergängen, Guards und einem Live-Zustandsdiagramm.Fortgeschrittene Reaktivität
  • 15WebSockets: Echtzeit, die das Netz überstehtEin typisierter Socket als Signals: Reconnect mit Backoff und Jitter, Heartbeat, ein Postausgang im Offline-Modus und SSR-Sicherheit.Echtzeit & offline
  • 15Optimistische Updates & RollbackEine sofortige UI, die ehrlich bleibt: Snapshot und Rollback, Antworten in falscher Reihenfolge, Idempotenzschlüssel.Echtzeit & offline
  • 15Offline-first: Service Worker & CachingDer Angular Service Worker: Caching-Strategien, Update-Hinweise und ein Postausgang für Änderungen, die offline entstehen.Echtzeit & offline
  • 16Web WorkersSchwere Berechnungen, ohne die UI zu blockieren: ein echter Worker in der Seite, Message Passing und wann es sich nicht lohnt.Fortgeschrittene UI & Performance
  • 16Riesige Listen: Virtual Scroll100.000 Zeilen ohne Ruckeln: CDK Virtual Scroll, itemSize, trackBy und die Alternativen (Paginierung, Infinite Scroll).Fortgeschrittene UI & Performance
  • 16Moderne Animationen & View Transitionsanimate.enter und animate.leave statt des veralteten @angular/animations, CSS-Transitions und View Transitions bei der Navigation.Fortgeschrittene UI & Performance
  • 16Memory Leaks finden und behebenSubscriptions, Timer und Listener, die ihre Komponente überleben – wie du sie in den DevTools findest und schließt.Fortgeschrittene UI & Performance
  • 17Sicherheit: XSS, Sanitizing & CSPWas Angular automatisch gegen XSS tut, wann bypassSecurityTrust gefährlich wird, dazu CSP mit Nonce, Trusted Types und XSRF.Sicherheit & Globalisierung
  • 17Authentifizierung: Tokens & RefreshEin Interceptor, der das Token anhängt, bei 401 einmal erneuert und die wartenden Requests wiederholt — dazu, wo du das Token aufbewahrst.Sicherheit & Globalisierung
  • 17OAuth 2.1 & OpenID Connect mit PKCEDer Authorization-Code-Flow mit PKCE Schritt für Schritt: Verifier und Challenge, State und Nonce, das ID-Token und warum ein BFF sicherer ist.Sicherheit & Globalisierung
  • 17Internationalisierung (i18n)$localize, das i18n-Attribut, ICU plural/select, ein Build pro Sprache vs. Übersetzungen zur Laufzeit und Formatierung nach Locale.Sicherheit & Globalisierung