Webcomponents im Detail

Ich berichte über meine gesammelte Erfahrung aus einem Projekt. Das Ziel, über eine internationale Entwicklung hinweg, eine einheitliche Corporate Identity (CI) für die grafischen User Interfaces (GUI) zu schaffen. Die Lösung sollte mit unterschiedlichen Web-Frameworks kompatibel sein, jedoch auch vollständig autark mit möglichst wenig Ressourcen funktionieren.

Dieser Text dient als Niederschrift eines Vortrags für einen Kunden.

Im oben genannten Projekt wurde sich für die WebComponents-Lösung entschieden. Diese wurden erstellt und in einer Component-Library gesammelt und als NPM-Pakete bereitgestellt.

Der Start eines solchen Projekts war mit der einen oder anderen Hürde geziert, da es zu diesem Zeitpunkt dieser Technologie noch keine bis wenig Erfahrungsberichte oder eine Empfehlung für eine Best-Practice gab. Bei solch einer Ausgangsposition rate ich, immer genügend Zeit in ein Proof of concept (POC) zu stecken.

Anhand der Dauer eines POCs, lässt sich der Verlauf, sowie der Erfolg oder Misserfolg eines Projekts bestimmen.

Bei der Entwicklung von WebComponentes gibt es keine, wie sonst üblich, vordefinierte Umgebung und Tools. Es liegt an uns, welche wir davon einsetzen wollen. Für den Start empfehle ich folgendes Setup, ich habe damit gute Erfahrungen gemacht:

TypeScript: Abgesehen der Typisierung, welche ich sehr gerne verwende, ist das Decorator-Feature bei der Entwicklung von WebComponents sehr hilfreich. Wir haben damit die Möglichkeit, die Definition von Properties so zu gestalten, wie wir es bereits aus anderen Frameworks kennen.

@Input() userName: string;

Build-Tool: Meine Empfehlung wäre WebPack, es eignet sich aber auch jedes andere Tool dafür. Sollen die Komponenten im Internet Explorer funktionieren, kommt man um ein transpile nicht herum. Handelt es sich um eine einzige Komponente, macht ein Code-Bundeling Sinn.

IDE: Meiner Meinung nach empfiehlt sich Visual Studio Code am besten, aufgrund der guten TypeScript Unterstützung.

Eine Beobachtung, die ich in diesem Projekt gemacht habe, es ist ein hoher Testaufwand zu beobachten. Browser ist hier nicht gleich Browser. Es kommt auf die verwendete Version und Betriebssystem an. So müssen 3 mögliche Faktoren (Browser, Browser-Version, OS) kombiniert getestet werden. Ich empfehle deswegen, genau zu definieren, welche Mindestanforderungen die WebComponentes erfüllen müssen.

Sollen WebComponents in bestehenden Frameworks wie Angular und React zum Einsatz kommen, ist dies ein weiterer Faktor in unserer Testlandschaft. Dies ist für mich ein besonders wichtiger Punkt. Angular und React arbeiten intern sehr unterschiedlich, daher sind Anpassungen innerhalb der Komponenten unvermeidlich.

Werden Daten in React über Attribute weitergereicht, kommen diese in einer WebComponent innerhalb des attributeChangedCallback an. Hingegen in Angular, wird direkt in eine Variable oder Property geschrieben. Wie es in Vue und Co aussieht, ist mir aktuell nicht bekannt.

Sollten Decorator möglich sein, empfehle ich, eine aussagekräftige Logik innerhalb eines solchen zu kapseln, z.B. der @Prop-Decorator. Dieser kümmert sich in allen weiteren Komponenten um das Problem. Wichtig: Um keine hartnäckigen Bugs einzubauen, empfehle ich, sollte ein tiefes Fachwissen über das verwendete Framework existieren.

Häufig ist es so, dass eine Änderung eines Attributes oder einer Property ein rerender (neu zeichnen) der Komponente verlangt. Hier gilt es folgendes zu beachten. Wichtig ist, dabei den aktuellen Zustand nicht zu verlieren, das heißt, ist eine User-Eingabe vom rendering betroffen, sollte diese nach dem Vorgang denselben Inhalt wie zuvor haben. Wird beim Tastenanschlag ein render ausgelöst, kann es schnell passieren ein unangenehmes Flackern zu erzeugen.

Um dieses Problem zu lösen gibt es folgende Varianten. Es wird eine eigene Logik definiert oder es wird sich einer bestehenden Bibliothek bedient. Für zweiteres eignet sich die Bibliothek hyperHTML. Diese Bibliothek vereinfacht vieles. Dennoch sollte hyperHTML ausreichend innerhalb eines POCs untersucht werden. Ich empfehle, sich frühzeitig Gedanken zu machen, welche Teile gezeichnet werden sollen, häufig reichen kleine Teile der UI aus.

Mir wurde beim Vortrag folgende Frage gestellt, die ich gerne festhalten möchte.

“In unserem Projekt wird ein UI Framework verwendet, welches ein globales Styling vornimmt. Ist es möglich, WebComponents ebenso davon stylen zu lassen.“

Im nächsten Moment kam ich auf die Idee, nutzen wir kein ShadowDom, so ist es möglich ein globales Styling zu verwenden. Wir diskutierten die Idee. Natürlich ist es möglich, WebComponents ohne ShadowDom zu verwenden, damit würde ein globales Styling funktionieren. Unter gewissen Punkten ist dieser Ansatz vertretbar, obwohl er etwas ungewöhnlich ist.

Uncaught TypeError: Failed to construct 'HTMLElement': Please use the 'new' operator, this DOM object constructor cannot be called as a function.

Diesem Fehler bin ich häufig begegnet. Ich finde ihn schwer verständlich und möchte ihn hier erklären. Es sieht so aus, als kann der Constructor nicht aufgerufen werden.

Nun haben wir zwei Lösungsansätze.

IE wird benötigt, muss ES5 verwendet werden. Da es bei ES5 keinen Constructor gibt (nur eine ähnliche Construktor-Funktion) kann dieser nicht gefunden werden. Entweder fehlen die notwendigen Polyfills oder die Reihenfolge ist falsch. Zuerst sollten die Polyfills geladen werden, dann die Komponenten.

IE wird nicht benötigt, kann auf ES6 umgestellt werden.

Ein fertiges Beispiel ist auf meiner Webseite zu finden. Es handelt sich um die Carousel-Component, wie über den Seitenquelltext zu sehen ist. Der verwendete HTML-Tag ist

<roda-carousel></roda-carousel>

Wenn ich zu diesem Thema begeistern oder bei einem Projekt unterstützen kann, stehe ich gerne als Referent oder Berater zur Verfügung.