© ecco/Shutterstock.com
Das Potenzial jenseits von Angular 9

Die Zukunft von Angular mit Ivy


Ivy ist in erster Linie für stark optimierte Bundles bekannt. Daneben bietet es aber auch einiges an Potenzial für künftige Features wie optionale Angular-Module, Zoneless Change Detection, dynamische Komponenten und Web Components.

Mit Angular 9 ist es endlich soweit: Der lang ersehnte Ivy-Compiler steht in einer abwärtskompatiblen Version zur Verfügung. Um den Übergang zur neuen Spielart von Angular nicht unnötig lang hinauszuzögern, ist Ivy auch schon standardmäßig aktiviert. Im besten Fall führt das ohne weiteres Zutun zu kleineren Bundles. Eine Verringerung um bis zu 40 Prozent ist möglich, abhängig von der Art der Anwendung. Doch Ivy steht für viel mehr als nur für kleinere Bundles. Ivy ist auch die Basis für künftige Features, die nach Angular 9 eingeführt werden.

Genau darum geht es in diesem Artikel. Ich möchte zeigen, welches Potenzial im Unterbau von Ivy schlummert und wie es die Zukunft von Angular beeinflussen kann. Dazu greife ich einige private APIs auf. Diese sind zwar nicht für den Produktionseinsatz gedacht, zeigen aber, mit welchen Ideen im Hinterkopf das Angular-Team Ivy entworfen hat und wo die Reise hingehen kann. Die hier verwendeten Beispiele finden sich in meinem GitHub-Repository unter [1]. Es handelt sich dabei um ein einfaches Dashboard (Abb. 1), zu dem sich dynamisch Kacheln mit Statistiken hinzufügen lassen.

steyer_ivy_1.tif_fmt1.jpgAbb. 1: Einfaches Dashboard als Beispielanwendung
steyer_ivy_2.tif_fmt1.jpgAbb. 2: Kleinere Bundles dank Ivy

Lazy Loading von Komponenten

Lazy Loading ist seit Angular 2 möglich. Allerdings nur auf Modulebene, denn der Angular-Compiler stellte bisher die zur Laufzeit benötigten Metadaten pro Modul bereit. Das ändert sich nun mit Ivy: Jede Komponente trägt ihre eigenen Metadaten in Form von statischen Eigenschaften mit sich. Davon bekommen wir nichts mit, weil Ivy diese Eigenschaften erst beim Kompilieren hinzufügt.

Dieses sogenannte Lokalitätsprinzip ermöglicht das nachträgliche Laden einzelner Komponenten. Sie lassen sich einfach mit Inline-Importen in die Anwendung holen:

import('../dashboard-tile/dashboard-tile.component').then(m => { const comp = m.DashboardTileComponent; [...] });

Die Frage ist jetzt allerdings, wie sich solche Komponenten anzeigen lassen. Eine Vorgehensweise, die bereits heute funktioniert, ist die Nutzung der ViewContainerRef eines Platzhalterelements (Listing 1).

Listing 1: ViewContainerRef

@Component({ … }) export class DashboardPageComponent { constructor( private injector: Injector, private cfr: ComponentFactoryResolver) { } @ViewChild('vc', {read: ViewContainerRef, static: true}) viewContainer: ViewContainerRef; add(): void { import('../dashboard-tile/dashboard-tile.component').then(m => { const comp = m.DashboardTileComponent;  // Only b/c of compatibility; will not be needed in future! const factory = this.cfr.resolveComponentFactory(comp); const compRef = this.viewContainer.createComponent( factory, null, this.injector); const compInstance = compRef.instance; compInstance.a = data[0]; compInstance.b = data[1]; compInstance.c = data[2]; compInstance.ngOnChanges(); }); } }

Das Beispiel bezieht die ViewContainerRef über ein ViewChild, das durch Angabe einer Template-Variable vc auf den Platzhalter verweist: <ng-container #vc></ng-container>

In dieser ViewContainerRef lässt sich anschließend die Komponente mittels createComponent instanziieren. Um dafür Dependency Injection zu ermöglichen, bekommt createComponent den aktuellen injector übergeben. Die Notwendigkeit, mit einem ComponentFactoryResolver die ComponentFactory der dynamischen Komponente zu ermitteln, ist ein Relikt aus vergangenen Tagen und wird in Zukunft wegfallen.

Wie das Beispiel auch zeigt, lassen sich nach dem Instanziieren die Eigenschaften der Komponente setzen. Auf dieselbe Weise könnte sich die Anwendung auch für Ereignisse registrieren.

Bootstrapping einzelner Komponenten

Angular-Module (NgModules) sind in Angular-Anwendungen, wie wir sie derzeit kennen, omnipräsent. Sie bieten zum einen die Möglichkeit zur Strukturierung und liefern zum anderen dem Angular-Compiler wichtige Kontextinformationen.

Dieser Umstand schlägt sich bis zum Bootstrapping der Anwendung durch. Hier ist ein Modul mit einer oder mehreren Bootstrap-Komponenten anzugeben:

platformBrowserDynamic().bootstrapModule(AppModule);

Ivy kennt dafür heute schon eine Alternative. Die derzeit noch private Funktion renderComponent erlaubt es, eine einzelne Komponente zu erzeugen und auf der Seite darzustellen: ɵrenderComponent(FlightComponent);

Auf diese Weise werden Angular-Komponenten ähnlich flexibel nutzbar wie ihre Gegenstücke in als leichtgewichtig geltenden SPA Frameworks. Wie der nächste Abschnitt zeigt, können davon auch auf Angular basierende Web Components profitieren.

Dass diese Methode privat ist, erkennt man am vorangestellten Sonderzeichen ɵ. Dieses API führt übrigens zu den kleinen Bundles, über die Google-Manager Brad Green auf der ng-conf 2019 gesprochen hat (Abb. 2).

Während sich demnach eine Hello-World-Anwendung mit öffentlichen Ivy APIs auf 109 KB reduzieren lässt, hat dieselbe Anwendung nur 14 KB, wenn das Bootstrapping mit renderC...

Neugierig geworden? Wir haben diese Angebote für dich:

Angebote für Gewinner-Teams

Wir bieten Lizenz-Lösungen für Teams jeder Größe: Finden Sie heraus, welche Lösung am besten zu Ihnen passt.

Das Library-Modell:
IP-Zugang

Das Company-Modell:
Domain-Zugang