Derzeit und schon seit geraumer Zeit werden die meisten Entwicklungen unter dem Dach eines Frameworks durchgeführt. Wenn wir uns auf das Frontend und Javascript konzentrieren, finden wir Dutzende von Frameworks. Es ist eine Herausforderung, grafische Oberflächenelemente wie Schaltflächen oder andere Komponenten wiederzuverwenden, wenn man dies möchte, da jedes von ihnen besondere Eigenschaften hat.
Was sind web components
Web components sind eine Reihe von Elementen aus verschiedenen standardisierten Technologien wie HTML, CSS und Javascript, die eine Struktur bilden, die ihre Verwendung in anderen Websites oder Anwendungen ermöglicht. Diese Technologien ermöglichen die Erstellung angepasster Elemente sowohl hinsichtlich der Funktionalität als auch des Erscheinungsbilds. Eine ihrer Stärken ist, dass sie Framework-agnostisch sind und daher in jedem Javascript-Framework verwendet werden können. Dadurch ist es möglich, eine Bibliothek gemeinsam genutzter Komponenten zu haben und gleichzeitig verschiedene Plattformen und Technologien zu nutzen. Dies kann sehr nützlich sein, um ein Markenimage auf einfachere Weise zu vereinheitlichen und aufrechtzuerhalten.
Das World Wide Web Consortium (W3C), auch bekannt als die Organisation, die das Internet, wie wir es heute kennen, gegründet hat, hat diese Methode im Jahr 2012 entwickelt, um alle grundlegenden Technologien des Webs zu standardisieren.
Warum Web components verwenden?
Die meiste Webentwicklung erfolgt unter einem Javascript-Framework wie Angular, Vue oder bekannten Bibliotheken wie React JS. Alle diese Frameworks und Bibliotheken sind für Entwickler sehr nützlich, da sie ihnen eine Reihe von Tools bieten, die die Entwicklung schneller und zuverlässiger machen.
Allerdings sind das nicht nur gute Nachrichten, denn Entwickler müssen häufig dieselben Komponenten in verschiedenen Projekten mit unterschiedlichen Frameworks oder Bibliotheken verwenden. Sie sind daher gezwungen, diese Teile mit doppeltem Code neu zu schreiben. Dies stellt ein Problem hinsichtlich der Wartung dar, da der Entwickler diese Änderungen so oft vornehmen muss, wie die Komponente repliziert wurde, um potenzielle Probleme zu beheben und neue Funktionen oder Anpassungen zu integrieren.
Dieses Problem kann durch den Einsatz von web components gelöst werden, die die Entwicklung individueller Komponenten mit HTML, CSS und Javascript ermöglichen, die nicht von Frameworks oder Bibliotheken abhängig sind. Mit anderen Worten bedeutet dies, dass der Entwickler sie nur einmal erstellen muss, um sie in allen Projekten verwenden zu können.
Es gibt auch einen anderen Fall, in dem die Verwendung von Web components interessant sein kann. Nehmen wir an, ein Unternehmen hat ein starkes Corporate Image, verwendet aber unterschiedliche Plattformen oder Webtools. Es kann schwierig sein, den Stil von Schaltflächen oder anderen Elementen mit demselben Design zu vereinheitlichen. Mit dem Web componentsansatz können Designer eine Sammlung von Teilen erstellen, die zum Corporate Image passen, und Entwickler müssen sie dank des gemeinsam genutzten Teilekatalogs nur einmal implementieren.
Web components Spezifikationen
Web components basieren auf vier Hauptspezifikationen, wie im Folgenden erläutert:
Benutzerdefinierte Elemente
Benutzerdefinierte Elemente sind eine Reihe von APIs, mit denen der Entwickler neue HTML-Tags erstellen kann. Sie können das Verhalten und die Art und Weise der Erstellung auf visueller Ebene definieren. Es gibt zwei Arten von benutzerdefinierten Elementen:
- Autonome benutzerdefinierte Elemente: werden zum Erstellen völlig neuer HTML-Elemente verwendet.
- Angepasstes integriertes Element: wird verwendet, um vorhandene HTML-Elemente oder andere web components zu erweitern.
Schatten-DOM
Mit der Shadow-DOM-API können Sie Fragmente des ursprünglichen DOM isolieren, sodass Sie die internen Elemente verbergen können, die ein größeres im DOM angezeigtes Element bilden. Das interne Verhalten ähnelt dem eines Iframes, bei dem der Inhalt vom Rest des Dokuments isoliert werden kann. Es gibt jedoch einen Unterschied: Mit dem Shadow-DOM bleibt die vollständige Kontrolle über den internen Inhalt erhalten. Dieser Prozess der Isolierung von Elementen von ihrer Umgebung wird als Kapselung bezeichnet und verhindert, dass CSS- und JavaScript-Code in andere benutzerdefinierte Elemente eindringt.
ES-Module
Bevor es ES-Module gab, hatte Javascript kein Modulsystem wie andere Sprachen. Um Javascript-Code in Anwendungen einzufügen, wurden Tags wie <script/>verwendet. Später kamen auch andere Möglichkeiten zum Definieren von Modulen auf, wie etwa CommonJS, aber keine davon wurde standardisiert.
ES-Module schienen eine Standardlösung für dieses Problem zu bieten. Jetzt ist es in Javascript ES6 integriert und ermöglicht es uns, einige Funktionen in einer Bibliothek zu gruppieren und sie in anderen Javascript-Dateien wiederzuverwenden.
HTML-Vorlagen
Mit diesen HTML-Vorlagen können Sie Codeausschnitte erstellen, die als HTML wiederverwendbar sind, aber beim Laden der Seite nicht sofort gerendert werden. Die Vorlagen können zur Laufzeit mithilfe von JavaScript in das Hauptdokument eingefügt werden, und die internen Ressourcen werden nur ausgeführt, wenn die Elemente in das Dokument eingefügt werden. Unabhängig davon, wie oft eine Vorlage verwendet wird, wird sie nur einmal gelesen, sodass eine gute Leistung gewährleistet ist.
Dieses System erstellt zunächst eine leere Vorlage, damit es nicht mit der übrigen Anwendung in Konflikt gerät, und rendert den Inhalt dieser Vorlage nur, wenn er benötigt wird, wodurch wiederum eine gute Leistung gewährleistet wird.
Kompatibilität
Die Kompatibilität von web components ist sehr groß. Alle Evergreen-Browser (Chrome, Firefox und Edge) unterstützen sie problemlos. Sie unterstützen alle APIs (benutzerdefinierte Elemente, HTML-Vorlagen, Shadow DOM und ES-Module).
Obwohl die Kompatibilität weitgehend ist, gibt es einige Ausnahmen, wie z. B. Internet Explorer und Safari. Im Falle von Internet Explorer ist die Inkompatibilität auf die Schließung durch Microsoft zurückzuführen, wodurch der Zugriff am 14. Februar 2023 entfernt wird. Bei Safari gibt es bestimmte Funktionen, die kompatibel sind, und andere, die es nicht sind. Die oben erläuterten autonomen benutzerdefinierten Elemente sind zu 100 % mit Safari kompatibel. Das Shadow DOM wurde jedoch noch nicht implementiert, und nach einer Debatte zwischen Google- und Apple-Ingenieuren im Jahr 2013 wurde entschieden, dass auch benutzerdefinierte integrierte Elemente nicht implementiert werden.
Herausforderungen von web components
Web components mussten sich verschiedenen Herausforderungen stellen, um ihren Platz zu finden und ihre Implementierung lohnenswert zu machen. Sie haben sich stark weiterentwickelt, es besteht jedoch noch Raum für Verbesserungen.
Integration mit allgemeinen Stilen
Der Umgang mit dem Überschreiben allgemeiner Stile in der Anwendung ist eine der Herausforderungen, mit denen web components konfrontiert waren und für die es derzeit etwas komplexe Lösungen gibt. Dafür gibt es mehrere Möglichkeiten:
- Verwenden Sie kein Shadow DOM: Sie können die Stile direkt zum benutzerdefinierten Element hinzufügen, allerdings bleibt der Code dadurch anfällig für versehentliche oder böswillige Änderungen durch Skripts.
- Verwenden Sie die Host-Klasse: Mit dieser Klasse können Sie ein benutzerdefiniertes Element aus dem Schatten-DOM auswählen und es auf eine bestimmte Weise formatieren.
- Verwenden benutzerdefinierter CSS-Eigenschaften: Die benutzerdefinierten Eigenschaften oder Variablen sind in den web components kaskadiert verbunden. Wenn Ihr Element also eine Variable verwendet, können Sie diese innerhalb von :root definieren und sie kann problemlos verwendet werden.
- Schattenteile verwenden: Mit dem neuen :part- Selektor können Sie auf einen Teil eines Schattenbaums zugreifen. Daher können Sie mit dieser neuen Methode einen bestimmten Teil eines benutzerdefinierten Elements formatieren.
- Stile als Zeichenfolge übergeben: Stile können als Parameter übergeben werden, um sie innerhalb des Blocks <style> anzuwenden.
Integration mit Formularen
Alle Typen von <input>-, <textarea>- oder <select> -Elementen im Shadow DOM sind nicht automatisch an das Formular gebunden, das sie enthält. Ursprünglich wurden dem DOM versteckte Felder hinzugefügt, aber dadurch wurde die Kapselung der Webkomponente aufgehoben.
Derzeit können wir mit der neuen ElementInternals- Schnittstelle eine Verbindung zum Formular mit benutzerdefinierten Werten herstellen und sogar Validierungen definieren. Sie ist in Chrome implementiert, aber für andere Browser ist ein Polyfill verfügbar.
Um zu demonstrieren, wie diese neue Schnittstelle funktioniert, erstellen wir eine grundlegende Komponente eines Formulars. Zunächst muss die Klasse einen statischen Wert namens formAssociated haben, der bestimmt, ob das Formular verbunden ist oder nicht. Wir können auch einen Rückruf hinzufügen, um zu sehen, wann es verbunden ist.
Anschließend wird im Konstruktor die Methode attachInternals() aufgerufen, die es der Komponente ermöglicht, mit dem Formular oder anderen Elementen zu kommunizieren, die Sichtbarkeit des Werts oder Validierung erfordern. Außerdem wird die Methode setValue implementiert, mit der der Wert im Formular festgelegt wird. Initialisiert auf eine leere Zeichenfolge.
Sobald dies erledigt ist, können Sie die Methode connectedCallback() erstellen , die ein Shadow DOM erstellt und die Änderungen überwacht, um sie an das übergeordnete Formular weiterzugeben.
Von diesem Punkt an können Sie das HTML-Formular erstellen, das die Webkomponente enthalten wird.
Abhängigkeitsspritze
Die Abhängigkeitsinjektion ist eine weitere Herausforderung, der sich web components stellen müssen. In vielen Fällen benötigen Entwickler beim Programmieren eine Abhängigkeitsinjektion, um ihre Komponenten wiederverwendbar zu machen.
Aus diesem Grund könnte man versuchen, die Abhängigkeitsinjektion über den Konstruktor durchzuführen, wie unten dargestellt.
Leider ist dies nicht gültig, da laut Spezifikation, wenn ein Element zu einem benutzerdefinierten Element wird, sein Konstruktor ohne Argumente aufgerufen wird und daher keine Abhängigkeiten übergeben werden können. Auch auf diese Weise könnte es auf eine alternative Weise gelöst werden, aber es würde nur funktionieren, wenn Sie diese Komponenten über Javascript und nicht direkt im HTML erstellen. In einem realen Fall würde es keinen Sinn ergeben, da Sie die web components über HTML hinzufügen möchten.
Darüber hinaus gibt es ein weiteres Problem: Wenn der Konstruktor aufgerufen wird, wird die Komponente nicht direkt in das DOM eingefügt. Wenn daher eine hierarchische Abhängigkeitseinfügung erforderlich ist, muss gewartet werden, bis der ConnectedCallback -Rückruf ausgeführt wird, der anzeigt, dass er bereits im DOM positioniert ist.
Glücklicherweise gibt es eine Lösung für dieses Problem. Um es zu lösen, müssen wir uns auf die Methode connectedCallback konzentrieren , da wir ab diesem Moment wissen, dass wir die richtige Hierarchie haben, um die Abhängigkeiten einfügen zu können. Um die Abhängigkeiten zu erhalten, können wir das im Browser integrierte Ereignissystem verwenden. Glücklicherweise sind sie synchron. Dank dieser Ereignisse können wir die Abhängigkeiten über sie anfordern und bereitstellen.
Wenn wir sie zum Zeitpunkt der Ausführung der Methode connectedCallback innerhalb der Webkomponente anfordern und sie von einer anderen Stelle des Codes aus bereitstellen, an der wir diese Abhängigkeiten haben, kann die Injektion problemlos durchgeführt werden.
Um diesen Prozess bei der Implementierung wesentlich einfacher zu gestalten, gibt es einige bereits implementierte Lösungen in Form von Bibliotheken, die uns alles bieten, was wir für die unkomplizierte Implementierung der Abhängigkeitsinjektion benötigen.
In der Dokumentation der Bibliothek WebComponents-DI können Sie anhand von Beispielen sehen, wie sie im Detail implementiert wird. Obwohl die Funktionsweise im Wesentlichen der zuvor erläuterten entspricht, wird die Abhängigkeit von connectedCallback angefordert und von der übergeordneten Komponente wird die Abhängigkeit mithilfe der Infrastruktur für synchrone Ereignisse bereitgestellt.
Lebensdauer einer Webkomponente
Der Lebenszyklus einer Webkomponente durchläuft verschiedene Phasen, wie etwa Definition, Konstruktion, Verbindung zur bestehenden Struktur und Trennung usw. Diese Methoden werden als Lebenszyklen bezeichnet und im Folgenden ausführlich beschrieben.
Definition des benutzerdefinierten Elements
Um das benutzerdefinierte Element zu registrieren, wird die Methode customElements.define() verwendet. Diese Methode ermöglicht die Registrierung eines benutzerdefinierten Elements, das ein HTMLElement erweitert. Um es auszuführen, sind einige Parameter erforderlich. Der erste ist der Name, der zweite ist die Klasse, die das Element definiert, und der dritte ist optional und ein Objekt mit Optionen, das die Erweiterung eines bereits vorhandenen benutzerdefinierten Elements ermöglicht.
Konstrukteur()
In web components ist der Konstruktor die erste Methode des Lebenszyklus und wird ausgeführt, sobald die Webkomponente initialisiert wurde. Um die Eigenschaften, Ereignisse und Methoden der Klasse, die er erweitert, HTMLElement, zu haben, ist es notwendig, super() aufzurufen.
Sobald super aufgerufen wurde, muss das neue Element auch dem Shadow DOM hinzugefügt werden. Wenn dies als „open“ (öffnen) erfolgt, ist es mit Javascript zugänglich, und wenn dies als „close“ (schließen) erfolgt, wird es geschlossen. Sobald es dem Shadow-Stamm hinzugefügt wurde, können Sie auf dessen Inhalt zugreifen oder sogar ein untergeordnetes Element hinzufügen, wie im obigen Codeausschnitt.
verbundenerCallback()
Diese Methode wird jedes Mal aufgerufen, wenn die Komponente zum DOM hinzugefügt wird. Wenn sie beispielsweise aus dem DOM entfernt, aber anschließend wieder hinzugefügt wird, wird sie ebenfalls ausgeführt. Diese Methode wird verwendet, um auf bestimmte Attribute oder untergeordnete Elemente zuzugreifen oder Listener hinzuzufügen.
AttributChangedCallback()
Mit dieser Methode werden Aktualisierungen konkreter Attribute empfangen. Dazu müssen diese Attribute zunächst in der statischen Methode observedAttributes() definiert werden. Nach der Definition wird die Methode attributeChangedCallback() nach jeder Attributänderung ausgeführt. Diese Methode hat drei Parameter, der erste gibt den Namen des geänderten Attributs an, der zweite den alten Wert und der letzte den neuen Wert. Das Attribut gilt erst dann als geändert, wenn die Methode this.setAttribute() ausgeführt wurde.
Attribute werden als serialisierte Daten gespeichert. Daher kann die Verwendung von Gettern und Settern zur Deserialisierung sehr nützlich sein.
adoptierterCallback()
Mit dieser Methode wird gemeldet, dass die Webkomponente von einem Dokument in ein anderes verschoben wurde. Sie wird nur ausgeführt, wenn die Methode document.adoptNode() aufgerufen wurde.
getrennterCallback()
Diese Methode wird nur aufgerufen, wenn die Webkomponente aus dem DOM entfernt wird, um mitzuteilen, dass sie nicht mehr angezeigt wird. Sie wird normalerweise verwendet, um Listener zu entfernen und sich abzumelden.
Integration mit Angular
Eine der Stärken von Web Components ist die Vielseitigkeit, die sie bei der Integration in andere Frameworks und Bibliotheken bieten. Um zu sehen, wie einfach es ist, eine Web Component mit einem bekannten Framework zu erstellen, zeigen wir als Nächstes ein einfaches Beispiel für die Erstellung einer Web Component mit Angular.
Um zu zeigen, wie man mit Angular eine Webkomponente erstellt, erstellen wir ein Angular-Projekt mit einer Webkomponente, die eine To-Do-Liste sein wird, um eine sehr einfache To-Do-Liste zu erstellen, und diese Webkomponente erhält den Namen der To-Do-Liste als Eingabe.
Der erste Schritt besteht darin, das Projekt und eine Komponente zu erstellen, in der die Aufgabenliste enthalten sein wird. Diese Komponente hat nichts Besonderes oder unterscheidet sich von einer normalen Angular-Komponente. Darüber hinaus verfügt diese Komponente, wie bereits erwähnt, über einen Input, der den Namen der Aufgabenliste enthält. Hier ist die Komponente .
Sobald die Komponente erstellt ist, müssen wir die Datei app.module ändern, um den Export der Komponente als Webkomponente zu ermöglichen. Dazu verwenden wir unter anderem die Angular Elements-Bibliothek, ein weiteres der vielen vorhandenen Tools zum Erstellen von web components. Alle Aktionen, die in dieser Datei ausgeführt werden müssen, werden unten detailliert beschrieben.
- Wir entfernen AppComponent aus Bootstrap, da es nicht mehr erforderlich ist, da wir das Projekt nur zum Exportieren der web components verwenden werden.
- Wir fügen die erstellte To-Do-Listenkomponente als EntryComponent hinzu.
- Wir installieren das Paket @angular/elements.
- Innerhalb des ngDoBootstrap-Hooks des Moduls verwenden wir die Methode createCustomElement , um die Komponente als Standard-Webkomponente zu kompilieren.
Hier ist die Datei zum besseren Verständnis der Änderungen.
Und von diesem Moment an, wenn das Projekt im Verzeichnis dist kompiliert wird, werden die Dateien mit den Namen runtime, main, scripts und polyfills angezeigt. Die erstellte Webkomponente kann in jedem anderen Projekt verwendet werden.
Werkzeugbau
Auch in puncto Tools kommen Web Components nicht zu kurz, da mehrere Optionen zur Auswahl stehen. Um Web Components auf einfache Weise zu erstellen und ihre Integration und Wartung problemlos zu gestalten, wurden mehrere Bibliotheken entwickelt, die dem Entwickler dabei helfen, diese Technologie flexibel zu implementieren.
All diese Tools bieten vor allem eine Umgebung, die ein besseres Entwicklungserlebnis ermöglicht und die Entwicklung beschleunigt. Die meisten dieser Tools werden unter anderem von großen Marken wie Apple, Porsche und Amazon verwendet hexagonal architecture.
Schablone
Stencil.js ist ein vom Ionic-Team entwickeltes Tool, das sich für andere Frameworks öffnen sollte, denn bis Stencil erschien, funktionierte Ionic nur mit Angular. Dank Stencil kann Ionic derzeit nahtlos mit React, Vue oder anderen Frameworks zusammenarbeiten.
Es handelt sich im Wesentlichen um einen Web Components-Compiler mit Vanilla Javascript, aber es ist noch viel mehr. Es hat einige der besten Funktionen anderer Frameworks. Um beispielsweise benutzerdefinierte Elemente zu optimieren, verwendet es einen virtuellen DOM wie React und ermöglicht serverseitiges Rendering, reaktive Datenbindung oder sogar asynchrones Rendering, das von React Fiber (der neuen React-Engine) inspiriert ist. Es unterstützt auch Typescript und JSX als Template-Engines und kann Lazy Loading verwenden, ohne dass Webpack erforderlich ist.
Weitere Informationen zu diesem Tool können Sie hier nachlesen.
Polymer
Ein weiteres der bekanntesten Tools für die Entwicklung von Web Components ist Polymer, das von Google entwickelt wurde und zunächst für die Entwicklung interner Projekte gedacht war, schließlich aber auf öffentlicher Ebene das Licht der Welt erblickte. Diese Bibliothek bietet eine Reihe von Polyfills (kleine Javascript-Codestücke), die Web Components nativ mit den meisten Browsern kompatibel machen.
Mit dieser Bibliothek können wir web components einfacher und schneller erstellen. Im Grunde genommen ermöglichen sie es uns, die von uns entwickelten web components wirklich mit den meisten Browsern kompatibel zu machen. So können Sie alle Ressourcen nutzen, die web components bereits haben, ohne auf Funktionalität verzichten zu müssen. Weitere Informationen zu diesem Tool finden Sie auf der Polymer Project- Site.
Möchten Sie mehr über technische Themen erfahren? Ich lade Sie ein, einen Blick auf den Blog von Apiumhub zu werfen . Jede Woche werden nützliche Inhalte zu den Themen Frontend-Entwicklung, Backend-Entwicklung, Softwarearchitektur und mehr veröffentlicht.