Web Components – bereit für ein neues Web?
Mit Web Components steht ein neuer Standard in den Startlöchern. Web 2.0 hat das Internet zwar auf ein neues Level gebracht – indem Benutzer auf Websites wie Facebook und Co. ihren eigenen Inhalt generieren können – doch das liegt bereits knapp zehn Jahre zurück. Seit damals hat das Web natürlich nicht Däumchen gedreht, sondern sich stetig weiterentwickelt. Die reinen Informationswebsites, die man heutzutage noch findet, sind moderne Relikte. Der Trend geht Richtung Cloud mit Apps im Browser. Sie unterscheiden sich vom Look-and-Feel kaum von Desktop-Programmen.
Trotz immer komplexeren Webprojekten ist mit HTML ein Standard im Einsatz, der vor 15 Jahren definiert und vor fünf Jahren das letzte Update bekommen hat. Dieser „Generationenunterschied“ führt dazu, dass das Markup moderner Web-Apps aus einem schwer lesbaren „Markup-Salat“ bestehen.
Web Components bringen Licht ins Dunkel. Wie? Ganz einfach!
Also, was sind nun diese Web Components?
In einem Satz erklärt: Mit Web Components kann man DOM-Elemente wie
oder
var MyTag = document.registerElement('my-tag'); document.body.appendChild(new MyTag());
Mit document.registerElement können wir unseren eigenen HTML-Tag deklarieren. Der Name muss einen Bindestrich „-“ enthalten. So unterscheidet der Browser zwischen den nativen Tags und den selbsterstellten Tags. Ein neues DOM-Element können wir mit „new MyTag()“ erstellen oder wir fügen unseren Tag einfach direkt ins Markup ein:
Jetzt wird’s spannend: Als zweites Argument können wir den Prototype unseres DOM-Elements definieren:
var MyTag = document.registerElement('my-tag', { prototype: Object.create(HTMLElement.prototype) });
Unser MyTag hat jetzt die Eigenschaften eines HTML-Elements, was auch standardmäßig der Fall gewesen wäre. Somit bewirken die letzten beiden Code-Teile dasselbe. Doch an dieser Stelle können wir eigene Methoden für unseren Tag deklarieren und auch von anderen DOM-Elementen erben – sogar von nativen:
var MySuperAwsomeSelect = document.registerElement('my-super-awesome-select', { prototype: Object.create(HTMLSelectElement.prototype), extends: 'select' });
Unser eigenes SuperAwesomeSelect hat jetzt denselben Prototype wie ein natives Select – was soviel bedeutet wie: Es sieht aus wie ein natives Select, es verhält sich wie ein natives Select und es würde wahrscheinlich auch wie ein natives Select riechen, wenn DOM-Elemente riechen würden. Jetzt können wir aber diesen Prototype unseres SuperAwesomeSelect um unsere eigenen Methoden und Eigenschaften erweitern:
var MySuperAwsomeSelect = document.registerElement('my-super-awesome-select', { prototype: Object.create(HTMLSelectElement.prototype, { doSomething: { value: function() { alert('here you go'); } } }), extends: 'select' });
Eigene DOM-Elemente können spezielle Methoden definieren, die zu bestimmten Zeitpunkten automatisch aufgerufen werden. Diese „Lifecycle callbacks“ sind: „createdCallback“, „attachedCallback“, „detachedCallback“ und „attributeChangedCallback“. Mit „detachedCallback“ erfährt man zum Beispiel, wenn ein Element aus dem DOM verschwindet. Dazu gab es bisher keine performante Lösung.
Things get awesome with „Shadow-DOM“.
„Shadow-DOM“ ist die Lösung für den am Beginn genannten „Markup-Salat“ – meiner Meinung nach die größte Errungenschaft von Web Components. Die Lesbarkeit ist besser wodurch sich die Komplexität des Markup verringert.
Kurz erklärt: Eigene DOM-Elemente können selber Markup erstellen und dieses im „Shadow-DOM“ quasi verstecken. Das versteckte Markup ist also außerhalb unseres eigenen DOM-Elements nicht sichtbar. Und das ist noch nicht alles! So hat jeder „Shadow-DOM“ seinen eigenen Style-Scope. Das bedeutet alle Styles, die im Shadow-DOM definiert werden, haben keinen Einfluss auf Elemente außerhalb unseres eigenen Elements.
Natürlich können eigene DOM-Elemente auch sichtbares Markup haben, falls wir das wollen oder brauchen. Ein geeigneter Platz um eigene Elemente mit Markup zu befüllen – sei es normales oder Markup im „Shadow-DOM“ – sind die zuvor erwähnten Callbacks:
var MyOwnParagraph = document.registerElement('my-p', { prototype: Object.create(HTMLParagraphElement.prototype, { createdCallback: { value: function() { this.innerHTML = 'I am not in the shadow dom'; var shadow = this.createShadowRoot(); shadow.innerHTML = 'I am in the shadow dom'; } } }), extends: 'p' });
Mit „createShadowRoot“ erstellen wir ganz einfach unser eigenes „Shadow-DOM“, dass wir wie gewohnt mit beliebigem Markup befüllen können. In diesem Beispiel bekommt der erweiterte Paragraph-Tag bei seiner Erstellung automatisch sein eigenes Shadow-DOM, dass sofort mit Markup befüllt wird.
So schön und gut das alles klingt, wird es doch noch seine Zeit dauern, bis Web Components als Standard in allen Browsern Einzug gefunden haben. Für alle, die es wieder einmal nicht erwarten können, gibt es mit Polymer eine JS-Library mit der man Web Components auch teilweise in älteren Browsern verwenden kann. Polymer befindet sich zwar selber noch im Entwicklungsstadium, ein Blick ist es aber auf jeden Fall wert.
Mein Fazit.
Die Front-End-Welt des Webs wird sich auf jeden Fall in Richtung Web Components bewegen. Ich persönlich freue mich sehr über diese Entwicklung. Das Prinzip, eigene Tags zu erstellen, die man durch Vererbung logisch verketten kann und das in Verbindung mit dem „Shadow-DOM“ bietet ein unglaublich mächtiges Werkzeug. Damit ist es möglich, die komplexen Anforderungen moderner Projekte nicht nur visuell, sondern endlich auch unter der Motorhaube sinnvoll zu modellieren.
Mit Web Components kann Markup in kleine gekapselte Pakete gebündelt werden, was zu einer Streuung der Komplexität führt. Dadurch wird das Front-End moderner Web-Apps wartbarer und verständlicher.
Ich freue mich schon auf Projekte mit Web Components und bin gespannt, was mit dieser Technologie im Web noch alles umgesetzt wird.