Hinweis:
Dieser Blogartikel ist älter als 5 Jahre – die genannten Inhalte sind eventuell überholt.
Nachdem mit Polymer 1.0 eine stabile Basis für produktive Anwendung der Bibliothek geschaffen wurde, ist es die Top-Priorität des Entwickler:innen-Teams, das Tooling rund um Polymer zu verbessern, damit Polymer nicht nur theoretisch, sondern auch praktisch zur Entwicklung von modernen Webapps eingesetzt wird. Dabei stehen generell nicht nur Entwicklungsgeschwindigkeit und Performance sondern auch die Wiederverwendbarkeit und korrekte Dokumentation von selbst erstellen Komponenten im Fokus.
In diesem Artikel wird gezeigt, welche Tools, die den Gebrauch von Polymer im Entwickler:innen-Alltag vereinfachen, heute schon bereitstehen oder sich in der aktiven Entwicklung befinden. Dabei wird ein prototypischer Workflow mit Build-Chain anhand der verfügbaren Werkzeuge skizziert, um einen Ausblick auf die zukünftigen Möglichkeiten zu geben.
Getting started
Damit die Entwicklung von eigenen Projekten mithilfe von Polymer auch für Anfänger möglichst einfach ist, hat das Polymer-Team das „Polymer Starterkit“ ins Leben gerufen. Dabei handelt es sich um eine Projektvorlage/ein Template, das eine funktionierende Entwicklungsumgebung bereitstellt, mit der direkt losgelegt werden kann. Zuvor muss allerdings die Node.js-Laufzeitumgebung und das als Build-System verwendete Gulp installiert werden. Als Dependency-Manager wird Bower eingesetzt. Die Vorlage beinhaltet nicht nur die Entwicklungsumgebung sondern auch ein kleines Beispielprojekt, das die verschiedenen Features aufzeigt und ein guter Startpunkt für ein eigenes Projekt ist. Beispielsweise ist ein Router-Element und ein rudimentäres Layout auf Basis von Paper-Elementen bereits inkludiert.
Zum Erzeugen eines neuen Projekts auf Basis des Polymer Starterkit kann entweder die Zip-Datei des neuesten Releases heruntergeladen und entpackt oder das Scaffolding-Tool Yeoman genutzt werden. Für Yeoman gibt es den Polymer-Generator, welcher die Installation des Starterkits und seiner Abhängigkeiten übernimmt.
Das Einrichten mithilfe von Yeoman funktioniert folgendermaßen:
1 2 3 |
npm install -g yo@1.4.8 && npm install -g generator-polymer@1.2.1 yo polymer:app |
Ohne Yeoman müssen die Abhängigkeiten von Hand installiert werden:
1 2 3 4 5 |
#laden und entpacken von polymer-starter-kit.zip npm install #installation der entwicklungsumgebung bower install #download der abhängigkeiten |
Nach dem Einrichten des Starterkits kann mit dem Befehl „gulp serve“ ein Entwicklungs-Webserver gestartet werden, der die Web-App zu Testzwecken anzeigt. Um die Feedback-Schleife während des Entwickelns möglichst kurz zu halten, horcht gulp auf Datei-Änderungen und lädt bei Bedarf die Web-App im Browser neu.
Der mit gulp realisierte Build-Prozess führt folgende Schritte aus:
- Optimieren von Bildern und Fonts
- Minifizieren von Stylesheets, Skripten und HTML-Code
- Konkatenation aller verwendeten Komponenten in eine einzelne HTML-Datei
Zusätzlich wird Javascript-Code mithilfe von JSHint auf mögliche Fehler untersucht. Im Kapitel „Deployment-Build“ werden die Besonderheiten des Prozesses genauer erklärt.
Mit „gulp test“ können die Unit-Tests der selbst erstellten Komponenten mit dem Web Component Tester ausgeführt werden.
Testen mit WCT
Wie jeder Code sollten mit Polymer erstellte Web Components vor dem Release gründlich getestet werden. Die „Unit“, die sich im Falle Polymer anbietet, ist die einzelne Komponente. Die Tests für eine Komponente werden dabei in einer HTML-Datei gekapselt:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
<!doctype html> <html> <head> <script src="../../webcomponentsjs/webcomponents.js"></script> <script src="../../web-component-tester/browser.js"></script> <link rel="import" href="../ph-listview.html"> </head> <body> <ph-listview id=“elementToTest“></ph-listview> <!-- ... --> </body> </html> |
In dieser Vorlage werden der Webcomponent-Polyfill, der Testrunner und die zu testende Komponente geladen. Im body wird das zu testende Element angelegt. Die Tests selbst stehen dann in einem script-Tag, das auf das Element folgt:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<script> suite('ph-listview', function () { test('viewType should be `default`', function () { var element = document.getElementById(’elementToTest’); assert.equal(element.viewType, 'default'); }); }); </script> |
suite, test und assert sind Methoden des Testframeworks mocha.js, die automatisch mit dem Web Component Tester (kurz WCT genannt) geladen werden. Mit ihnen ist es nun möglich, Unit-Tests zu formulieren. Diese werden vom Kommandozeilen-Client „wct“ ausgeführt, und zwar in allen installierten Browsern, für die Treiber zur Automatisierung vorhanden sind. Zur Fernsteuerung der Browser setzt der WCT Selenium ein.
Leaky State verhindern
Ein Problem, das beim oben gezeigten Beispiel auftritt, ist der sog. Leaky State – das zu testende Element wird für die einzelnen Tests nicht zurückgesetzt, es behält also seinen internen Zustand, z.B. geladene Daten oder Einstellungen. Dadurch kann ein Testfall einen anderen beeinflussen und die Tests können beispielsweise nicht mehr in beliebiger Reihenfolge ausgeführt werden. Nun wäre es natürlich möglich, das Element vor jedem Test zurückzusetzen. Doch wie es so oft im Polymer-Umfeld heißt: „There is a component for that“. In diesem Fall heißt die erforderliche Komponente test-fixture und kümmert sich darum, dass jeder Test mit exakt den selben Bedingungen startet:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<test-fixture id="listView"> <template> <ph-listview></ph-listview> </template> </test-fixture> <script> //... setup(function (done) { elementToTest = fixture('listView'); done(); } |
setup wird vor jedem Test ausgeführt und erzeugt mit der Hilfsmethode fixture für jeden Test eine neue Instanz der zu testenden Komponente, wie im Template der Fixture definiert.
Durch eine Integration von Saucelabs ist es zusätzlich möglich, alle Komponenten-Tests auch in der Cloud in vielen verschiedenen Browsern auszuführen, die lokal nicht installiert sind oder nicht installiert werden können.
Der Deployment-Build
Theoretisch sind mit Polymer entwickelte Webcomponents ohne irgendeine Form von Build-Prozess direkt in Web-Apps nutzbar – sie müssen nur per <link rel=“import“ href=“/pfad/zur/komponente.html“> eingebunden werden. In der Praxis treten dabei allerdings verschiedene Probleme auf. Die größte Schwierigkeit bildet dabei die Performance – wenn jede Komponente in einer eigenen Datei gespeichert ist, muss jeweils ein HTTP-Request ausgeführt werden. Mit HTTP 1.1 bedeutet das für jede Komponente den Overhead einer eigenen TCP-Verbindung, zusätzlich können nur 5 simultane Verbindungen zu einem Server erstellt werden. Je nach Geschwindigkeit der Internetanbindung des Nutzers kann so die Ladezeit einer Web-App enorm ansteigen. Das Tool Vulcanize, das in Build-Systeme wie gulp oder grunt integriert werden kann, schafft Abhilfe, indem es alle verwendeten Komponenten zu einer einzelnen Datei zusammenfasst, die mit einem einzelnen HTTP-Request vom Browser geladen werden kann. Zusätzlich wird HTML und Javascript-Code minifiziert, d.h. Whitespaces werden entfernt und Variablennamen werden auf möglichst wenige Zeichen verkürzt. Durch die Link-Elemente in den einzelnen Komponenten, die die Abhängigkeiten zwischen den Komponenten genau beschreiben, ist es möglich, nur die Komponenten in die resultierende HTML-Datei zu laden, die wirklich benötigt werden. So muss, wenn eine Komponenten-Bibliothek wie die Paper-Elemente verwendet wird, nicht die ganze Bibliothek eingebunden werden, wenn nur einige wenige Komponenten wirklich genutzt werden.
Ein Problem an einer zusammengefassten Datei, die HTML und Javascript-Code beinhaltet, ist die Verletzung der Content Security Policy (CSP). Diese Maßnahme zur Erhöhung der Sicherheit von Webapps sieht vor, dass eingebundenes Javascript nur aus dedizierten Javascript-Dateien (also kein Inline-Javascript) von vertrauenswürdigen Domänen stammt. Auf diese Weise sollen Cross-Site-Scripting-Angriffe verhindert werden. Das Tool Crisper ergänzt Vulcanize und kümmert sich um die Einhaltung von CSP, indem es alle Javascript-Snippets der einzelnen Komponenten zusammenführt und so HTML und Javascript trennt. Dadurch müssen zwar zum Laden der Web-App 2 getrennte HTTP-Requests durchgeführt werden, diese können jedoch parallelisiert werden und verzögern daher den Aufbau der Seite nicht wesentlich. Zur einfacheren Verwendung ist Vulcanize und Crisper in Polybuild zusammengefasst – die Konfiguration der Build-Chain vereinfacht sich so.
Es wäre noch denkbar, auch die CSS-Skripte zu minifizieren, allerdings muss dies mit Vorsicht getan werden, da Polymer CSS mit Selektoren wie :host und Funktionen wie @apply() erweitert, die u.U. nicht korrekt minifziert werden, da die Tools sie nicht kennen.
Bevor jedoch der Build überhaupt ausgeführt wird, sollte die Richtigkeit des eigenen Codes sichergestellt werden. Dies kann zum einen durch Ausführen von Unit-Tests mit dem Web Component Tester geschehen. Zum anderen ist es möglich, den Code auf verdächtige Stellen zu untersuchen, die wahrscheinlich nicht so funktionieren wie von dem/der Programmierer:in beabsichtigt (sog. Code-Smells). Im Kontext von Polymer gibt es dafür das Tool polylint, das zum Beispiel Referenzen prüft (sind in Templates verwendete Funktionen überhaupt definiert?) oder die korrekte Verwendung der Polymer-Bibliothek validiert (sind benötigte Attribute gesetzt?). So können gerade bei unerfahrenen Polymer-Entwicklern Fehler früh erkannt werden.
Momentan noch in der Entwicklung befindet sich ein Tool, um Polymer-Stylesheets zu normalem CSS zu kompilieren, damit dieser Schritt nicht die Startup-Zeit im Browser erhöht. Nähere Informationen zu diesem Tool, das die Build-Chain ergänzen könnte, sind zum gegenwärtigen Zeitpunkt noch nicht verfügbar.
Documentation-driven Development
Auch die beste Komponente bringt keinen Mehrwert, wenn niemand weiß, wie diese verwendet werden kann. Da das Teilen bzw. Wiederverwenden von Komponenten der Grundgedanke von Webcomponents ist, wird im Polymer-Ökosystem besonders viel Wert darauf gelegt, die Dokumentation und Bereitstellung von eigenen Komponenten möglichst einfach und schmerzlos zu gestalten – auf diese Weise bilden sich schnell große Bibliotheken von Komponenten und Entwickler:innen können sich auf die spezifischen Teile ihrer Anwendungen konzentrieren und sich nicht gezwungen, das Rad immer wieder neu erfinden zu müssen. Wenn zuerst die Dokumentation einer API oder Komponente und erst danach die Implementierung erstellt wird, spricht man von Documentation driven Development (DDD). Durch die bereitgestellten Tools des Polymer-Toolset soll ein solcher Entwicklungsstil einfacher gemacht und belohnt werden. Auch hier heißt es: „There is a component for hat“ – die Komponente iron-component-page erstellt für eine gegebene Komponente automatisch eine (ebenfalls auf Polymer basierende) Dokumentations-Seite mitsamt funktionierender Demo. Inhalte der Seite werden automatisch aus HTML-Kommentaren und Javascript-Kommentaren aus dem Quellcode der Komponente geladen:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
<html lang=""> <head> <script src="../webcomponentsjs/webcomponents.js"></script> <link rel="import" href="../polymer/polymer.html"> <link rel="import" href="../iron-component-page/iron-component-page.html"> </head> <body unresolved> <iron-component-page></iron-component-page> </body> </html> |
Die Dokumentation kann in Markdown verfasst werden, so sind auch komplexe Dokumente möglich. Wird eine Demo im gleichen Verzeichnis gefunden, so wird diese auch mit eingebunden. Mithilfe des Scripts gp.sh oder dem Befehl gh im Polymer-Yeoman-Generator (yo polymer:gh) lässt sich diese Dokumentation automatisch als Github-Page veröffentlichen – die Schwelle, eine ansprechende und einheitliche Dokumentation für die selbst erstelle Komponente zu veröffentlichen, ist also so niedrig wie möglich gelegt.
UI-Design in Polymer
Wenn komplexe Oberflächen mit Polymer-Komponenten umgesetzt werden, ist es oft unpraktisch, das Layout in Code zu formulieren, das Ergebnis im Browser zu betrachten und dann wieder den Code anzupassen. Tools, bei denen Oberflächen auf grafischem Wege entwickelt werden können, schließen die Feedback-Schleife und machen die Bearbeitung so einfacher und intuitiver. Für die native App-Entwicklung existieren solche Tools in Xcode und Android Studio. Mit dem Polymer Designer gibt es auch für auf Webkomponenten basierende Web-Apps ein entsprechendes Gegenstück. Für Polymer 1.0 wurde ein komplett neues Programm (Designer 2) begonnen, das sich noch in der aktiven Entwicklung befindet. Für Polymer 0.5 Elemente gibt es mit Designer 1 bereits eine nutzbare Version. Der Designer ist selbst als Web-App implementiert, kann aber mithilfe des Electron-Frameworks als herkömmliches Programm installiert werden. Dabei wird die gleiche technische Grundlage wie für Githubs Open Source Editor Atom genutzt.
Viele auf Polymer basierende Webapps nutzen die Paper-Elemente, da sie so ohne Aufwände ein ansprechendes, auf Material Design basierendes Layout generieren können. Um die Standard-Material-Design-Farben anzupassen und ein ansprechendes Farbschema zu wählen, kann auf www.materialpalette.com zurückgegriffen werden. Diese Website generiert automatisch aus einem gewählten Farbschema eine HTML-Datei, die in die eigene Polymer-App eingebunden werden kann und das Aussehen für alle Paper-Elemente von einer zentralen Stelle aus ändert.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
<!-- Palette generated by Material Palette - materialpalette.com/blue-grey/grey --> <!-- Replace the one that comes in their starter kit --> <style is="custom-style"> :root { --dark-primary-color: #455A64; --default-primary-color: #607D8B; --light-primary-color: #CFD8DC; --text-primary-color: #FFFFFF; --accent-color: #9E9E9E; --primary-background-color: #CFD8DC; --primary-text-color: #212121; --secondary-text-color: #727272; --disabled-text-color: #BDBDBD; --divider-color: #B6B6B6; /* Components */ /* paper-drawer-panel */ --drawer-menu-color: #ffffff; --drawer-border-color: 1px solid #ccc; --drawer-toolbar-border-color: 1px solid rgba(0, 0, 0, 0.22); /* paper-menu */ --paper-menu-background-color: #fff; --menu-link-color: #111111; /* paper-input */ --paper-input-container-color: rgba(255, 255, 255, 0.64); --paper-input-container-focus-color: rgba(255, 255, 255, 1); --paper-input-container-input-color: #fff; } </style> |
Die hier definierten Styles werden automatisch von den Paper-Elementen importiert und überschreiben die Default-Styles.
Component-Hosting leicht gemacht
Es ist oft praktisch, ein Content-Delivery-Network zu nutzen, um externe Abhängigkeiten einer Web-App aufzulösen – der Aufwand, die Abhängigkeiten selbst zu hosten, entfällt; bei großflächiger Verbreitung haben viele User bereits die Abhängigkeit von Besuchen anderer Websites im Browser-Cache und es stehen weltweit performante Server zur Verfügung – auf diese Weise wird die Web-App schnell geladen. Polygit bietet ein einheitliches Interface, das beliebige auf Github gehostete Komponenten als CDN bereitstellt. So lädt beispielsweise die folgende URL die Paper-Button Komponente in Version 1.0.2 :
http://polygit.org/paper-button+v1.0.2/components/paper-button/paper-button.html
Der Aufbau der URL ist dabei wie folgt: /[<configurations>/]components/<component>/<path>
<component> und <path> spezifizieren die geladene Komponente und den Pfad innerhalb des Repositories der Komponente, <configurations > sind eine oder mehrere Repositories (mit / getrennt), in denen nach <component> gesucht wird. Zusätzlich kann die Version angegeben werden, * steht für das neueste Release. Die <configuration> super-gif+sjmiles+* würde also zum Repository super-gif der Organisation sjmiles in der neuesten Version aufgelöst werden. Da der Anfang der Import-URLs immer derselbe ist, empfehlen die Polygit-Entwickler:innen, mithilfe des base-Tags den Pfad-Prefix für Includes festzulegen und beim tatsächlichen include nur noch den Komponenten-Namen anzugeben, der anschließend automatisch aus den angegebenen Repositories ausgewählt wird:
1 2 3 4 5 |
<base href="http://polygit.org/polymer+v1.0.3/vellum-*+sjmiles+*/components/"> <link href="polymer/polymer.html" rel="import"> <link href="vellum-grid/vellum-grid.html" rel="import"> |
Polygit ist mit Vorsicht zu nutzen, da es zwar die Vorteile eines CDNs für die Auslieferung eigener Komponenten (hohe Bandbreite und Georedundanz) bietet, aber auch die Nutzung von Tools wie Polybuild, die Komponenten zusammenfassen, verhindert – mit Polygit muss für jede Komponente mindestens ein HTTP-Request durchgeführt werden. Es muss von Fall zu Fall entschieden werden, ob sich die Verwendung dieses Tools lohnt.
Links & Literatur
- https://github.com/PolymerElements/polymer-starter-kit/releases
- https://www.polymer-project.org/1.0/docs/#pre-processing-stylesheets
- http://polygit.org/
- https://github.com/Polymer/web-component-tester
We’re hiring!
Tapetenwechsel gefällig? Wir sind auf der Suche nach begeisterten Frontend-Entwickler:innen, die unsere Projektteams im Umfeld von JavaScript, HTML und CSS unterstützen und auch vor innovativen Themen wie AngularJS und Progressive Web Apps nicht zurückschrecken. Jetzt Bewerben!
Weiterlesen
Mehr Informationen zu unseren Dienstleistungen rund um die Web-Entwicklung gibt es auf unserer Website. Unser Portfolio umfasst außerdem die Anwendungsentwicklung für Android & iOS mit speziellem Fokus auf Enterprise-Apps. Für direkten Kontakt schreibt an info@inovex.de oder ruft an unter +49 721 619 021-0.