Blazor WebAssembly 5 und die Kopplung an .NET 5 - guter Ausblick für die Zukunft
Blazor WebAssembly 5 ist im November 2020 als Teil von .NET 5 sechs Monate nach dem Erscheinen der ersten offiziellen Version (3.2.0) released worden und profitiert an diversen Stellen von Verbesserungen in .NET 5. Microsoft plant weitere .NET-Versionen im Jahresrhythmus (https://github.com/dotnet/core/blob/main/roadmap.md). So dürfte mit .NET 6.0 und damit mit Blazor WebAssembly 6 im November 2021 zu rechnen sein.
Die Kopplung an den Releasezyklus von .NET gibt Blazor-Developern mehr Planungssicherheit. Es ist davon auszugehen, dass sich das Blazor-Team und das .NET-Team bei Microsoft intensiv zu neuen Features für die jeweils kommende Version austauschen werden. Durch diesen Rückenwind dürfte die Weiterentwicklung von Blazor WebAssembly deutlich beschleunigt werden. Gleichzeitig zeigt die Kopplung mit dem Releasezyklus von .NET auch, wie wichtig Blazor WebAssembly für Microsoft als Technologie bereits geworden ist – ein wichtiger Aspekt für die Betrachtung der Zukunftssicherheit von Blazor WebAssembly.
Neue Features in Blazor WebAssembly 5
Blazor WebAssembly 5 (und Blazor allgemein) bringt eine Fülle von neuen Features mit. In die Liste ist auch viel Feedback von Entwicklern eingeflossen, die auf GitHub direkt Wünsche an das Blazor-Team formuliert haben.
- Performance-Verbesserungen
- CSS-Isolation
- Neue InputFile-Komponente
- Neue InputRadio- und InputRadioGroup-Komponenten
- Komponentenvirtualisierung
- ontoggle Event-Unterstützung
- UI-Focus in Blazor-Apps setzen
- Eigene Attribute für Validierungsklassen
- Unterstützung für IAsyncDisposable
- JavaScript-Isolation und Objektreferenzen
- Debugging-Verbesserungen
- Microsoft Identity v2.O und MSAL v2.O
- WASM Prerendering
- Trimming/Linking-Verbesserungen
- Browser Compatibility Analyzer
- Lazy Loading von Assemblies
- Aktualisierte Globalization-Unterstützung
- Forms-Komponenten unterstützen Display-Namen
- Catch-all Routenparameter
Schauen wir auf die Details der wichtigsten Features.
Leicht verbesserte Developer Experience in Blazor WebAssembly 5
In den bisherigen Blazor WebAssembly-Versionen waren Debugging und Developer Tools noch stark verbesserungswürdig. Mit .NET 5 macht Blazor WebAssembly hier einen Schritt nach vorne, auch wenn weiterhin viel Luft nach oben bleibt. Grundsätzlich ist das Debugging sowohl innerhalb von den Browsern als auch innerhalb von Visual Studio stabiler geworden. Grundlegendes Debugging funktioniert jetzt auch in Visual Studio for Mac. Mit der Experience vom Debugging normaler .NET-Anwendungen auf Desktop oder dem Server ist das Debugging von Blazor WebAssembly jedoch noch nicht vergleichbar.
Browser Compatibility Analyzer – Probleme rechtzeitig erkennen
Bisher musste sich ein Entwickler vor der Nutzung von Assemblies oder Nuget-Paketen selbst Gedanken dazu machen, ob die neue Funktionalität mit Blazor WebAssembly kompatibel ist. Die Kombination von Browser-Sandbox und WebAssembly-VM verbietet beispielsweise Funktionen wie direkter Zugriff auf das Dateisystem, Multi-Threading oder Netzwerkprotokolle abseits von HTTP 1.1, HTTP/2 und WebSockets.
Microsoft liefert für die aktuelle Blazor-Version daher den sogenannten Compatibility Analyzer. Das heißt, wenn man Assemblies oder Nuget-Packages referenziert, die nicht innerhalb des Browsers ausführbar sind, also eine unsupported Platform haben, dann wird schon während des Builds ein Fehler angezeigt.
Hot Reload oder Live Reload in Blazor WebAssembly 5
Reload als Entwicklungs-Feature bei Blazor WebAssembly ist in einer einfachen Variante vorhanden. Es ist ein bisschen verquer, nämlich über das Kommando dotnet watch run
. Dieses Kommando sorgt im Hintergrund für eine ständige Überwachung des Projekts und stößt bei Veränderungen von Dateien einen Build an. Zusätzlich wird im Browser eine Einblendung gezeigt, dass jetzt ein Reload händisch im Browser ausgeführt werden kann. In der allerneuesten Version von Visual Studio 2019, nämlich die Version 16.8, kann dotnet watch run
direkt ausgeführt werden – der Umweg über einen separate Commandline entfällt.
Eine bessere Alternative kann das kommerzielle Tool LiveSharp sein. LiveSharp implementiert echtes Hot Reload für Blazor WebAssembly und spart so sehr viel Entwicklungszeit.
Für .NET 6.0 ist mit besserem integrierten Hot Reload zu rechnen, denn Steve Sanderson, dem Master-Architekt hinter Blazor und Blazor WebAssembly, ist laut Meldungen in den sozialen Netzen gerade am Bauen und am Basteln.
Optimierte Anwendungsgröße in Blazor WebAssemby 5
Neu bei Blazor WebAssembly 5 ist, dass die Anwendungsgröße kleiner geworden ist, denn in .NET 5 gibt es das sogenannte App Trimming. App Trimming ist es sowas ähnliches wie Tree Shaking, das man vielleicht aus anderen SPA Frameworks kennt. In den Blazor WebAssembly Templates und in den Build Tasks ist es automatisch angeschaltet. Man muss aber aufpassen: Wenn man beispielsweise etwas macht wie .NET Reflection oder irgendwelche anderen dynamischen Code-Lademechanismen oder sogar Code-Erzeugungsmechanismen, die innerhalb von Blazor WebAssembly überhaupt funktionieren würden, dann kann das natürlich einen unangenehmen Seiteneffekt haben. Deswegen muss immer sehr aufmerksam und früh getestet werden, ob der Application Trimmer nicht zu radikal durch das eigene Projekt geht.
Beim Standard-Template von Blazor WebAssembly optimiert der App Trimmer ein paar hundert Kilobyte weg – ein guter Wert, da das Template nur wenig anspruchsvollen Code enthält und das Projekt nicht besonders komplex ist. Der App Trimmer wird automatisch angestoßen, wenn ein Release Build angestoßen wird (bspw. durch dotnet publish -c Release
).
Da App Trimming im Build Zeit kostet, kann es während der Entwicklung oder beim Publishing z.B. über einen CI/CD auf eine Staging-Umgebung ganz einfach über eine entsprechende Property im C#-Projectfile abgeschaltet werden.
Verbesserte Runtime Performance in Blazor WebAssemby 5
Das .NET- und das Blazor-Team hat für Version 5 sehr stark daran gearbeitet, die Runtime und den IL Interpreter schneller zu bekommen. Je nach Szenario ist eine 2-4x bessere Geschwindigkeit bei der Komponentendarstellung möglich. In den Kundenprojekten, bei denen Thinktecture Teams zu Blazor berät, konnten wir eine deutliche Steigerung der “perceived performance”, also der gefühlten Geschwindigkeit, feststellen. In einem konkreten Feature wurden zum Beispiel Daten für eine umfangreiche Listendarstellung als JSON von der API geholt und dann angezeigt. Mit Blazor WebAssembly 3.2 dauerte dieser Vorgang noch zwischen 0,9 bis 1,2 Sekunden. Durch die Runtime-Optimierungen von Blazor WebAssembly 5 sind es jetzt nur noch 0,3 Sekunden für das Rendering der Komponente.
Die Optimierung der Blazor-Runtime liefert besonders dann deutlich mehr Geschwindigkeit, wenn es darum geht, String Handling oder Dictionary Handling zu machen und vor allem bei der JSON-Serialisierung und JSON-Deserialisierung.
Schnellerer App Start durch Server Side Prerendering
In Blazor WebAssembly besteht eine Anwenderhürde darin, dass wir eine relativ große Application Size haben, welches beim ersten Aufruf der App heruntergeladen werden muss. Dieses App-Bundle wird zwar durch den neuen App Trimmer kleiner, aber am Ende des Tages kann es sich vor allem bei langsamen, mobilen Verbindungen durchaus noch zäh anfühlen. In .Blazor WebAssembly 5 gibt es dafür nun Server Side Prerendering, um den initialen Aufruf so schnell wie möglich zu bekommen. Blazor kombiniert dazu Features aus Blazor Server, um den Einstiegspunkt in die App schon auf dem Server vorzurechnen und schaltet für die weitere Ausführung kurze Zeit später auf Blazor WebAssembly um, sobald alle Bestandteile des App-Bundles geladen worden sind.
Für SSR muss der Code einer Blazor WebAssembly-Anwendung schon signifikant umgebaut und entsprechend vorbereitet werden. Das Resultat ist allerdings sehr überzeugend: der Aufruf einer SSR-optimierten App erfolgt wirklich unmittelbar; die App ist für den Anwender nahezu “sofort” verfügbar.
Vorsicht ist allerdings geboten, wenn die App komplexe Abläufe wie z.B. clientseitige Authentifizierung über OAuth und über OpenID Connect aufweist. Hier kann es ganz schön tricky werden und bedingt viel Blazor-Erfahrung bei der Implementierung eines solchen Pre-Renderings.
Virtualize – große Datenmengen und Listen performant anzeigen und bedienen
Viele Apps müssen umfangreiche Listen mit Daten darstellen. Die Performance der Darstellung kann aber sichtbar leiden, wenn tausende Datensätze einfach in den DOM geschrieben werden. Auch moderne Browser neigen dann schnell zu einer ruckelnden Darstellung.
Typische Gegenmaßnahmen sind Patterns wie Paging oder Endless Scrolling. Die Implementierung dieser Patterns ist jedoch nicht trivial und zeitlich durchaus umfangreich. Blazor WebAssembly 5 bietet hierfür das neue Feature Virtualize
in Form einer eigenen Komponente, die es mit zwei Features gibt.
Im ersten Fall lädt man über einen Web-API-Call z.B. alle Daten in den Speicher der App und bindet das dann an diese Virtualize-Komponente. Virtualize sorgt dann dafür, dass man wirklich immer nur die Daten im Document Object Model bindet, die man auch sieht. Dazu werden entsprechende Berechnungen aus Viewport-Größe und über die Höhe der jeweils angezeigten Zeilen, z.B. in einer Tabelle, automatisch vorgenommen.
Im zweiten Fall, wenn es um besonders viele Daten in einer Liste geht, kann man eine Vorpartitionierung beim Laden der Daten durch Paging implementieren. Damit kann man die In-Memory-Datenhaltung von Virtualize optimieren, in dem durch fachlich definiertes Paging immer nur eine überschaubare, sinnvolle Menge an Datensätzen geladen wird.
Verbessertes Komponentenmodell in Blazor WebAssembly 5
Eine weitere wichtige Verbesserung gibt es im Komponentenmodell von Blazor WebAssembly 5. In .NET 3.1 (also Blazor 3.2) mussten alle Styles in eine große app.css
geschrieben werden. Es gab also keine Möglichkeit, out-of-the-box Component-Styles zu machen, um so echt gekapselte Komponenten zu bauen. Das ist jetzt in .NET 5 anders. Hier hat man die Möglichkeit, sozusagen Styles nur für meine Komponente zu definieren, so wie man es auch aus anderen SPA-Frameworks kennt. Von Hause aus unterstützt Blazor WebAssembly 5 gekapselte Komponenten-Styles auf Basis von CSS. Mit der Open Source-Komponente LibSassBuilder
ist das gleiche Ergebnis auch mit SASS möglich.
Hinzu kommt die Möglichkeit, dass man mit Blazor WebAssembly in .NET 5 nun auch komplett isolierte JavaScript-Dateien als JavaScript-Modules schreiben kann. Diese Module kann man dann in der gewünschten Razor-Komponente importieren und muss nicht immer alle Skripte in der index.html
inkludieren.
Lazy Loading für Komponenten
Ein Entwickler kann schon vor .NET 5 eine Komponentenbibliothek – eine so genannte RCL (Razor Class Library) – erstellen, in der Razor-Komponenten weggekapselt werden. Blazor WebAssembly 5 bringt nun die Möglichkeit mit, diese RCLs als DLLs je nach angeforderter Route der App nachzuladen. Allerdings ist es wirklich nur das Nachladen von einer DLL. Es besteht noch keine Möglichkeit, Initialisierungscode ablaufen zu lassen und es fehlen noch Hooks, um eigenen Init-Code für nachgeladene DLLs ausführen zu können. Lazy Loading in Blazor WebAssembly bringt also eine Kapselung, beziehungsweise Modularisierung, die Apps schneller und die Entwicklung einfacher machen kann.
Zusammenfassung
Mit Blazor WebAssembly 5 ist das Blazor-SPA-Framework gefühlt erwachsener geworden. Die Kopplung an den Release-Zyklus von .NET bringt Sicherheit für die zukünftige Weiterentwicklung von Blazor. Durch die enge Zusammenarbeit des Blazor-Teams und des .NET-Teams dürften letztendlich beide Projekte profitieren.
Das Blazor-Team hat in Version 5 an vielen relevanten Stellen des Frameworks sinnvoll optimiert: bessere Performance, kleinere App-Size, schneller App-Start durch SSR, modularisierte Komponenten – Entwicklungsteams dürften mit diesen Verbesserungen zufrieden sein. Blazor WebAssembly sollte daher durchaus von jedem Team das bereits sehr viel .NET-Wissen besitzt und zukünftig webbasierte Cross-Plattform-Apps schreiben möchte, ernsthaft und sorgfältig als mögliches SPA-Framework evaluiert werden.