5. Oktober 2021
Web Components entwickeln und testen
Dies ist eine Fortsetzung meines vorherigen Artikels „Custom Elements mit Vue Reactivity”. Hier werde ich meine Gedanken über die Herausforderungen teilen, denen ich bei der Einrichtung von Entwicklungs- und Unit-Testing-Umgebungen begegnet bin, ohne dabei die Accessibility-Bedenken für ein Webkomponenten-Projekt zu vergessen.
Fokus auf die Developer Experience
In der Vue.js-Entwicklung sind wir verwöhnt, wenn es um die Developer Experience (DX) oder die “Experience, die Entwickler*innen haben während sie ein digitales produkt nutzen oder daran arbeiten“. Von der erstklassigen Dokumentation über Browser-Erweiterungen und eigenständige Vue-Entwickler-Tools bis hin zu meinungsstarken Paketen für Routing, State Management und Unit Testing war das Vue-Ökosystem immer entwicklerzentriert und einsteigerfreundlich. Gute DX ist daher ein echter Key Value, auf den die Maintainer von Softwareprojekten hinarbeiten sollten, um die langfristige Nachhaltigkeit ihrer Projekte oder ihrer Nutzer*innen in der Community zu gewährleisten.
Beim Experimentieren mit Custom Elements bei der Entwicklung von vue-uhtml wurde der Mangel an Entwickler-Tooling (oder zumindest der Mangel an Dokumentation über Entwickler-Tooling) mit guter DX schnell offensichtlich. Bis heute gibt es keine Standardlösung in der Webentwicklung, um einen einfachen Entwicklungsserver aufzusetzen, der Vanilla HTML, CSS und JavaScript — die zugrundeliegenden Webtechnologien, auf denen Custom Elements aufbaut — bereitstellt. Ich habe mich entschieden, die Überlegungen zur Entwicklererfahrung für das vue-uhtml-Projekt auf drei Bereiche zu beschränken:
- Wie können Entwickler*innen vue-uhtml verwenden, um eine UI-Bibliothek zu entwickeln
- Wie können Entwickler*innen Komponenten, die mit vue-uhtml gebaut wurden, einem Unit-Test unterziehen?
- Wie können Entwickler bei der Entwicklung mit vue-uhtml auf Probleme der Barrierefreiheit (Accessibility) achten?
Die richtige Entwicklungs-Instanz für Custom Elements
Storybook ist ein beliebtes und einfach zu verwendendes Open-Source-Tool für die isolierte Erstellung von UI-Komponenten. Angesichts meiner bisherigen Erfahrungen mit Storybook für Vue-basierte Projekte, war dies eine natürliche Option für die UI-Entwicklung mit vue-uhtml. Storybook’s Web Components flavour machte diese Entscheidung noch einfacher, da es offiziell unterstützt und gut dokumentiert ist. Ein möglicher Nachteil bei der Verwendung von Storybook für Web Components ist die Verwendung der lit-html Templating Utility zur Erstellung von „Stories“ für Ihre Komponenten. Das lit-html Projekt ist übrigens die Bibliothek, mit der Evan You sein eigenes Custom Elements Projekt implementiert hat. Im Fall dieses Projekts ist die Notwendigkeit, Komponenten in einer etwas anderen uhtml-Syntax und „Stories“ in der lit-html-Syntax zu implementieren, objektiv eine negative Erfahrung für Entwickler*innen und muss für eine breitere vue-uhtml-Community weiter in Betracht gezogen werden.
Eine große Hürde bei der Entwicklung von Custom Elements ist ein Ansatz für die Implementierung von Stilen und CSS über das gekapselte Shadow-DOM, insbesondere wenn auch CSS-Pre- und Postprozessoren verwendet werden. Dieses Problem wird normalerweise während des Build-Prozesses gelöst, wenn Tools wie Webpack oder Rollup CSS-Transformationen orchestrieren, bevor sie die verarbeiteten Stile bündeln und an der richtigen Stelle einfügen. Front-End-Framework-CLI-Tools wie vue-cli-service, Vite oder create-react-app abstrahieren einen Großteil der zugrunde liegenden Verarbeitung und Erstellung sowohl für Entwicklungs- als auch für Produktionsumgebungen. Zum Beispiel müssen sich die meisten Vue-Entwickler*innen nicht darum kümmern, wie eine Vue-Komponente aus einer einzigen Datei von Webpack oder Vite kompiliert und auf einem lokalen Port bereitgestellt wird, wenn „yarn serve“ ausgeführt wird. Das bietet eine großartige DX, aber wahrscheinlich nicht etwas, das kurzfristig für die Vue-uhtml-Entwicklung leicht zu erreichen wäre.
Zusammengefasst waren dies die Schritte, die ich unternommen habe, um eine Storybook-basierte Entwicklungsumgebung mit anständiger DX einzurichten, um UI-Komponenten mit vue-uhtml zu erstellen:
- Konfigurieren eines einfachen Rollup-Projekts zur Verarbeitung von vue-uhtml definierten Custom Elements für Entwicklung und Produktion.
- Konfigurierung von Rollup, sodass es das `src`-Verzeichnis überwacht, um die Komponenten in einem `dev`-Verzeichnis zu kompilieren
- Konfigurieren von Storybook für Web Components und schreiben von component stories unter Verwendung der aufgerollten Ausgabekomponentendefinitionen im Verzeichnis `dev` (statt `src`)
- Gleichzeitige Ausführung von Rollup und Storybook über ein `dev` script
Das Ausprobieren dieser Schritte könnte in Zukunft die Grundlage für ein eigenes CLI von vue-uhtml sein, oder um Vite für einen ähnlichen Zweck zu erweitern oder zu verwenden.
Unit-Testing für Custom Elements
Meine nächste Überlegung war die Möglichkeit, Unit-Tests für Vue-uhtml-Komponenten auf einfache Weise zu schreiben und auszuführen. Nachdem ich zuvor über einen Unit-Testing-Ansatz für Vue.js-Komponenten gesprochen hatte, war ich sehr daran interessiert, das Prinzip des „Schreibens von Tests, die die öffentliche Schnittstelle der Komponente bestätigen“ anzuwenden. Bevor ich überhaupt an das Schreiben von Komponententests denken konnte, musste ich das am besten geeignete und gut unterstützte Tooling auswählen. Vue’s Dokumentation über das Testen und das eigene vue-test-utils Paket macht diese Wahl zu einer ausgemachten Sache mit Jest als umfassendes Test-Framework und der Verwendung der Wrapper-basierten API von vue-test-util, um Komponenten in einer isolierten jsdom-Umgebung einzubinden. Während jsdom seit Version 16 eine Custom Elements Implementierung zur Verfügung stellt, werden andere Web Components APIs, einschließlich Shadow DOM, nicht unterstützt oder sind nicht zuverlässig genug um nützlich zu sein.
Da es sich bei Custom Elements um eine browserbasierte Webtechnologie handelt, besteht ein gängiger Work-Around der Beschränkungen von jsdom darin, Puppeteer zu verwenden, um Tests mit Custom Elements durchzuführen, die in echten Browsern gerendert werden. In der Praxis ist dies jedoch in der Regel nicht die praktischste Lösung, da „Boilerplate“-Code erforderlich ist, um zu den Komponenten auf einer bereitgestellten HTML-Seite zu navigieren.
Um die DX zu verbessern und den Unit-Testing-Ansatz für Custom Elements zu streamlinen, haben das Team von Open Web Components ein Testpaket mit dem treffenden Namen @open-wc/testing bereitgestellt, das „Testbibliotheken kombiniert und konfiguriert, um den Aufwand für das Schreiben von Tests zu minimieren“. Auch wenn die fehlende Auswahl an Testläufen oder Assertion-Bibliotheken (@open-wc/testing verwendet Mocha bzw. Chai mit Puppeteer) einschränkend erscheinen mag, ist der positive Kompromiss eine klare Dokumentation und prägnante Beispiele, die beim Schreiben von Komponententests helfen.
Potenzieller Fehler: `shadowRoot.mode`
Die Abschirmung der Custom Elements Funktionen wird durch die Möglichkeit unterstützt, den shadowRoot
Modus einer Komponente auf ”closed”
zu setzen, wodurch verhindert wird, dass die internen Funktionen des Schattenstamms von JavaScript aus zugänglich sind.
Dies ist eine Funktion, die per default auf „closed“ gesetzt ist, wenn Komponenten mit vue-uhtml erstellt werden. Dies hat eine potentielle Fehler-Implikation, indem es Testskripte daran hindert, die internen Features der Komponenten zu bestätigen. Um zu verhindern, dass man in diese Falle tappt, sollten Komponenten, die auf Custom Element basieren, es den Entwickler*innen einfach erlauben, mit einem „offenen“ Shadow Root Modus definiert zu werden, wenn sie in Tests genutzt werden.
Das folgende Beispiel beschreibt die Tests für eine benutzerdefinierte Checkbox-Komponente, die:
- Behauptet, dass der ursprüngliche
checked
Value alsfalse
gilt - Behauptet, dass der
checked
Value alstrue
gilt, wenn sein Attribut übergeben wird - Behauptet, dass der
checked
Value alstrue
gilt, nachdem der Input geklickt wurde
Entwicklung mit Rücksicht auf`a11y`
Digitale Barrierefreiheit im Web, oder Web Accessibility (a11y
) war in der Vergangenheit ein Bereich, der in der Entwicklung und im Design gleichermaßen übersehen wurde und oft eher als Kunst als exakte Wissenschaft angesehen wurde. Es gibt zwar kein einziges Tool oder eine Methode, die alle Probleme in Bezug auf a11y
in der Webentwicklung löst — allerdings haben bedeutende Fortschritte bei den Werkzeugen in der Web-Entwicklung die Integration der Richtlinien für die Zugänglichkeit von Web-Inhalten (Web Content Accessibility Guidelines, WCAGs) in die Workflows ermöglicht.
Obwohl der Einsatz solcher Entwickler-Tools die eigentliche Aufgabe der Erstellung barrierefreier Websites und Anwendungen nicht löst, helfen sie den Entwickler*innen, sich während der Entwicklung des Themas `a11y`
bewusster zu werden als danach. Ein solches Tool, das die Entwickler*innen bei der Entwicklung mit `a11y`
unterstützt, ist axe, das einen Open-Source-Regelsatz für die automatische Validierung der Barrierefreiheit bereitstellt. Der axe-Regelsatz kann wiederum in `a11y`
-Validierungs-Plugins in anderen Entwickler-Tools verwendet werden. Ich war in der Lage, ein axe-basiertes `a11y` Plugin für Chai mit @open-wc/testing in mein vue-uhtml Komponenten Projekt zu integrieren.
Das axe-Plugin für Chai ermöglicht es Entwickler*innen, die a11y
-Validierung automatisch als Teil ihres TDD- oder BDD-Workflows durchzuführen.
Take-Aways
Die Developer Experience (DX) im Zusammenhang mit der Entwicklung eines auf Custom Elements basierenden Projekts zu berücksichtigen, ist sehr ähnlich wie das Nachdenken über die User Experience bei der Entwicklung von Front-End-Websites und -Anwendungen. Anstelle einer visuellen Benutzeroberfläche ist die API eines Tools/Bibliothek/Frameworks das Medium der End-User*innen (in diesem Fall der Entwickler*innen), um ihre Aufgaben zu erledigen. Diese kleine DX-Übung hat mich dazu gebracht, die durchdachten Beiträge zu schätzen, die Open-Source-Maintainer leisten, um ihre Tools und Dokumentationen für die breitere Development Community benutzerfreundlich zu halten.