1 Angular - mertenhanisch/ng-architecture GitHub Wiki
Grundlegende Architektur
Der Angular-Workspace ist ja nicht immer unbedingt übersichtlich und eigentlich auch stark darauf ausgelegt, nur eine App zu programmieren. Das mag für viele genau das sein, was SPA wohl bedeutet. Bei meiner Arbeit habe ich aber festgestellt, dass es einfach "zu eng gedacht" ist. Die Probleme, die sich da viel zu leicht einschleichen, sind krude Abhängigkeiten mit Kreisen, wozu es leider auch Empfehlungen von Angular gibt, wie man die nutzbar macht (forwardRef).
Je nach Umfang des Projekts kommt man normalerweise schnell zu einem Punkt, wo man spezielle Funktionalitäten in Libraries auslagern möchte, weil man sie dann doch an verschiedenen Stellen einsetzen will, oder man stellt fest, dass ein Feature plötzlich so unabhängig ist, dass es sich problemlos beim nächsten Projekt einsetzen ließe.
ng new
Jeder Angular Workspace beginnt mit ng new MyApp
. Ein unterschätzter Parameter dieses Befehls ist --createApplication=false
Das sorgt dafür, dass es erst mal nur einen leeren Workspace gibt, in dem man dann per "ng generate application" eine App anlegen kann. Der Unterschied? Wenn man ng new
ohne aufruft, landet der Source der App quasi im Root-Verzeichnis, wenn man nachträglich die App generiert, landet der Source im Verzeichnis "projects". Dort würden auch im ersten Fall nachträglich generierte Libraries landen, man hätte dann also schon mal die erste Unsauberkeit in seinem Repository.
Nächster Schritt: Angular ist noch nicht wirklich dazu bereit, ein Projekt komplett mit seinen Abhängigkeiten zu kompilieren. Man muss manuell erst die nötigen Libraries kompilieren, damit die im dist-Verzeichnis liegen, bevor man dann die App kompiliert. Wenn man aktiv an einer Library arbeitet, kann das schon echt nervig sein. Man startet den Watcher auf der Library (wartet den ersten Durchlauf ab), startet dann einen zweiten Watcher für die App und hofft, dass das alles halbwegs ineinander greift. Meist geht es, ab und an muss man die Watcher einfach mal neustarten, weil die sich verhaspeln. Das passiert häufiger, wenn man neue Dateien, Module usw. erstellt.
nx
Vor kurzem hab ich nx entdeckt und es schon erfolgreich in einem anderen Projekt integriert. Unsere Projekte will ich auch noch umstellen. Die organisieren den Workspace etwas anders, pflegen die Abhängigkeiten der Projekte untereinander und man kann mit einem Befehl alle Abhängigkeiten in einem Rutsch kompilieren. Außerdem haben die einen guten Buildcache. Wenn du also einen neuen Workspace startest, solltest du das in Betracht ziehen. Ein lustiges Goodie: du arbeitest in einem Branch an einem neuen Feature und hast überall kleine Änderungen gemacht. Natürlich willst du die Tests laufen lassen, damit du sicher sein kannst, nichts kaputt gemacht zu haben. Nx kann herausfinden, welche Stellen du im Vergleich zum main-Branch angefasst hast und welche Tests das betrifft und kann dann nur die Tests ausführen, die betroffen sind. Hilft beim inner-dev-loop.
bundle size & caching
Angular ist nicht gerade berühmt für seine kleine Bundlesize. Jupp, da kommen schnell diverse Kilo bis Mega zusammen, wenn man nicht aufpasst. Bei unserem neuen System habe ich extrem viel mit einzelnen NgModules gearbeitet, quasi jede Hauptroute ist ein eigenes NgModule, manchmal sogar noch unterteilt in weitere Module. Das gepaart mit Lazy Loading überall, sorgt dafür, dass Angular von sich aus schon ganz viel Codesplitting macht. Der erste Block kann immer noch relativ groß sein, aber man kann es dadurch schon gut im Griff behalten. Die zweite Möglichkeit, die man nutzen sollte (meiner Meinung nach heutzutage eigentlich unverzichtbar), ist ein ServiceWorker und PWA - ich gehe davon aus, dass du das sowieso nutzen würdest. Mir geht es dabei gar nicht so sehr um Offline-Fähigkeiten (das ist ein Feld, wo man eine Menge Energie reinstecken kann - Zweiwegesynchronisation ist der Horror), sondern darum, dass der ServiceWorker in erster Linie dafür gedacht ist, alle Assets und Scripte der App zu cachen. Damit ist nur der aller erste Load langsam, danach ist die App sofort da. Beim Entwickeln ist es manchmal etwas herausfordernd, die Änderungen am Code auch in den Browser zu kriegen (Reload-Button in Chrome gedrückt halten: Cache leeren und komplett neuladen - ein wunderbares Feature), aber wir behelfen uns damit, dass der ServiceWorker sowieso nur in der Produktivversion aktiv ist. Zweiter Pluspunkt des ServiceWorker: Er kann ein Update der App im Hintergrund laden, informiert dann das Programm und das kann dann seinem User mitteilen: Hey, drück mal F5, um das Update zu installieren (es kann natürlich auch selbst einen Reload machen), und das Update ist dann sofort da, weil es schon im Browsercache liegt. Bundlesize? Sind nicht mehr wirklich relevant heutzutage - es ist jedenfalls kein Hauptgrund mehr gegen ein Framework, egal welches.
https://angular.io/guide/service-worker-intro https://blog.angular-university.io/angular-service-worker/
ts configuration
Wenn man neu startet, sind "strict templates" ein Muss. Komplettes Typechecking in Templates - welch Wohltat.
https://angular.io/guide/template-typecheck
Ich kenne nicht viele Editoren, Angular bearbeite ich aber bevorzugt mit VS Code und der Angular Language Service Extension. Ich vermisse nichts. TypeScript kann viel "type inference", aber man sollte an den wichtigen Stellen immer manuell einen Type defineren/annotieren usw. Je mehr man seine Absichten ausdrückt, desto eher kann dir der Compiler dabei helfen.
Praxis
Templates
ngFor
Wenn ngFor, dann trackBy! Eine der wichtigsten Regeln überhaupt. Vermutlich könnte man eine Linter-Regel schreiben, die das anmeckert.
Weitere Stichworte
Stichworte, die uns bei unserem Workshop helfen werden: Model-View-Update (MVU), Redux, State-Management, Finite State Machines, RxJS Du solltest wissen, was ein Store, State, Action, Reducer, Dispatcher ist. Wichtige Observable-Operatoren: map, mapTo, switchMap, catchError, debounceTime, distinctUntilChanged, takeUntil, shareReplay, combineLatest, of, defer