S

super-dev — full-stack

@super-dev.app · Full-stack · ★ offen für Aufträge
12,8k Abonnenten·47 Videos·Aktiv seit 2017

Full-Stack-Entwickler .NET / Angular mit DevOps-Erfahrung auf Azure Cloud. Auch zu Hause mit Flutter + Firebase. Ich entwickle Produkte, deploye sie und überwache sie.

Zurück zu den Artikeln
ANGULAR
ANGULAR

Eine Angular-App auf zoneless + Signals umstellen

Artikel 1 von 4 — Angular 21 in der Praxis
Zoneless, Signals, resource(), @defer, SignalStore — modernes Frontend, für echte Projekte.

Jahrelang stützte sich Angular auf zone.js , um zu wissen, wann die Change Detection erneut ausgelöst werden muss: ein Monkey-Patch sämtlicher asynchroner Browser-APIs. Das funktioniert, ist aber eine teure Blackbox. Seit Angular 21 kann man mit provideZonelessChangeDetection() vollständig darauf verzichten und die Signals die Reaktivität steuern lassen.

Warum zone.js abschaffen

zone.js fängt setTimeout , Promises, DOM-Events ab und löst bei jedem Ereignis einen globalen Erkennungszyklus aus. In einer großen App werden dabei Tausende von Bindings geprüft, obwohl sich nur drei geändert haben. Der zoneless-Modus kehrt die Logik um: nichts wird neu gerendert, solange kein im Template gelesenes Signal seine Änderung gemeldet hat.

  • Kleineres Bundle: eine Abhängigkeit von ~100 kb entfällt
  • Lesbare Stack-Traces: keine zone.run -Frames mehr überall
  • Gezielte Erkennung: nur Komponenten, die vom geänderten Signal abhängen, werden markiert

Den zoneless-Modus aktivieren

Alles spielt sich in der Anwendungskonfiguration ab. Man entfernt provideZoneChangeDetection und hängt den zoneless-Provider ein:

TypeScript
1import { provideZonelessChangeDetection } from '@angular/core';
2import { bootstrapApplication } from '@angular/platform-browser';
3
4bootstrapApplication(AppComponent, {
5 providers: [
6 provideZonelessChangeDetection(),
7 provideRouter(routes),
8 ],
9});

In feingranularer Reaktivität denken

Im zoneless-Modus muss der gesamte Zustand ein Signal sein , sonst aktualisiert sich das Template nicht mehr. Man ersetzt veränderliche Felder durch signal() , abgeleitete Werte durch computed() und Seiteneffekte durch effect() :

TypeScript
1@Component({
2 selector: 'app-cart',
3 changeDetection: ChangeDetectionStrategy.OnPush,
4 template: `Total : {{ total() }} €`,
5})
6export class CartComponent {
7 protected readonly items = signal<CartItem[]>([]);
8 protected readonly total = computed(() =>
9 this.items().reduce((sum, item) => sum + item.price * item.quantity, 0),
10 );
11}

Die Fallstricke kennen

Legacy-Code, der setTimeout(() => this.value = x) ausführt, ohne ein Signal zu verwenden, aktualisiert die View nicht mehr. Gleiches gilt für RxJS-Subscriptions: man braucht entweder toSignal() oder muss signal.set() im subscribe aufrufen. Bei Tests wechselt man Vitest auf zoneless und ersetzt fakeAsync / tick durch await fixture.whenStable() . Die offizielle Dokumentation beschreibt jeden Fall im Detail im guide zoneless .

Zoneless macht eine App nicht magisch schneller. Es macht Reaktivität explizit : man weiß genau, warum etwas neu gerendert wird — und genau das verändert alles beim Debugging.
super-dev — portfolio.app
// Weiter in ANGULAR
Eine DOOM-artige Engine im Browser, mit drei Backends
11 min • 1,4k Aufrufe
Daten laden mit resource() und httpResource()
7 min • 3,6k Aufrufe
@defer und der neue Control Flow: weniger JS beim Start
6 min • 2,9k Aufrufe