How-To

SkateJs: Die Bibliothek für Web-Komponenten im Praxiseinsatz

(Abbildung: Shutterstock/ Elle Aon)

Wiederverwendbare Web Components sparen Entwicklern jede Menge Arbeit und Zeit. Wer selbst eine Komponente entwickeln will, kann mittlerweile auf hilfreiche ­Bibliotheken zurückgreifen. Wie das genau funktioniert und was es zu beachten gilt, zeigt die Arbeit mit SkateJS.

Wer Entwicklungszeit einsparen kann, der lässt sich das in der Regel nicht zweimal sagen – Web Components helfen dabei: Die wiederverwendbaren Komponenten lassen sich ohne zusätzlichen Aufwand über Custom-Elements an verschiedenen Stellen in Webprojekten einsetzen. Seit 2018 sind die Web-­Components-Standards in nahezu allen Browsern implementiert. Dank ­Polyfills, also Libraries, die neue, eventuell noch nicht unter­stützte Funktionalitäten nachliefern, lassen sie sich auch in ­älteren Browsern nutzen.

Mit der Web-Components-Bibliothek SkateJS können Entwickler entsprechende Komponenten erstellen. Die Library erfreut sich immer größerer Beliebtheit: In den vergangenen ­Monaten haben sich die Downloadzahlen von ­SkateJS von 60.000 fast auf 120.000 pro Monat verdoppelt. Wie aber funktioniert das Erstellen von Webkomponenten mit SkateJS genau? Das soll das folgende Beispiel zeigen, bei dem eine Komponente mit SkateJS und LitHTML entwickelt wird, die die Wetterdaten zu einem bestimmten Ort ausgibt.

Web Components mit SkateJS und LitHTML

SkateJS abstrahiert einige der nativen Schnittstellen. Im Prinzip betrifft das bei SkateJS vor allem das Rendering und die Entwicklung der Komponentenklasse. Das eigentliche Benutzen einer Webkomponente erfolgt dann mit nativen Bordmitteln.

SkateJS-Komponenten lassen sich in drei große Bestandteile gliedern: Für das Rendering im DOM ist ein Renderer erforderlich, der mit SkateJS kompatibel ist. Dazu zählen Out-of-the-Box LitHTML, Preact und React. SkateJS bietet auch die Option, einen eigenen Renderer zu benutzen. Das macht die Library letztlich mit nahezu jedem Renderer kompatibel.

Im Gegensatz zu vielen anderen Web-Component-Librarys arbeitet SkateJS mit den nativen Web-Component-API. Sie gehören ­zusammen mit Mixins und dem Renderer zum Grundaufbau von SkateJS-Components. (Abbildung: Aaron Czichon/t3n)

Im Gegensatz zu vielen anderen Web-Component-Librarys arbeitet SkateJS mit den nativen Web-Component-API. Sie gehören ­zusammen mit Mixins und dem Renderer zum Grundaufbau von SkateJS-Components. (Abbildung: Aaron Czichon/t3n)

Die zweite Komponentenvariante sind die sogenannten Mixins: abstrakte Sub-Klassen, die für die Definition eigener Sub-Klassen genutzt werden können. Die Mixins von SkateJS definieren verschiedene Lifecycle-Hooks einer Komponente. Die verwendeten Mixins sind davon abhängig, wie die Komponenten genutzt werden: ob mit einem Renderer, als Component oder mit einem Kontext.

Der dritte Teil sind die nativen Web-Component-API. Im Vergleich zu anderen Web-Component-Bibliotheken basiert SkateJS auf der nativen Implementierung der Webkomponenten. Somit sind alle API der Web-Component-Spezifikation ohne weiteres auch mit Skate zu nutzen.

Erstellen einer SkateJS-Umgebung: So klappt es

Für ein neues Projekt mit SkateJS wird zunächst ein NPM-Projekt initialisiert (npm init -y). Für den lokalen Build-Prozess verwenden wir Babel für die Transpilierung und Webpack für das Packaging:

$ npm install babel-core babel-loader babeö-preset-stage-0 webpack webpack-cli --save-dev

Wenn nun die Tools für den Build installiert sind, benötigen wir die Libraries, die wir zur Entwicklung brauchen. In diesem ­Beispiel verwenden wir LitHTML, eine kleine, effiziente ­Javascript-Library, als Renderer:

$ npm install skatejs lit-html @skatejs/renderer-lit-html @webcomponents/webcomponentjs --save

Um das Setup zu komplettieren, hinterlegen wir jetzt in der ­­­package.json noch die Scripts für den Build und den Watch-­Prozess.

„scripts“: {
  „build“: „webpack --mode production“,
  „start“: „webpack --mode development --watch“
}

Außerdem benötigen wir die Konfigurationen für Babel und ­Webpack.

// .babelrc
{
  „presets“: [„stage-0“]
}
```
```
// webpack.config.js
module.exports = {
    module: {
       rules: [
    {
      use: „babel-loader“
    }
      ]
    }
};

Die erste Webkomponente definieren

Damit wir eine Webkomponente schreiben können, die auch mit Events arbeiten kann, benötigen wir ein paar Hilfefunktionen in Form der Mixins. Das nachfolgende Mixin beschreibt ein normales HTML-Element, das um selbst definierte Events erweitert wird. Da ein normales HTML-Element nur Events kennt, die vom W3C festgelegt und in die Browser implementiert worden sind, müssen wir dieses Interface manuell erweitern.

// src/util.js
import { emit, withComponent } from „skatejs/dist/esnext“;
import withRenderer from „@skatejs/renderer-lit-html/dist/esnext“;
// Mixin for auto-defining functions that emit events.
const withEvents = (Base = HTMLElement) =>
  class extends Base {
    static get observedAttributes() {
      (this.events || []).forEach(e => {
        const name = `on${e[0].toUpperCase() + e.substring(1)}`;
        Object.defineProperty(this.prototype, name, {
          get() {
            if (!this.__events[e]) {
              this[name] = () => {};
            }
            return this.__events[e];
          },
          set(fn) {
            this.__events[e] = detail => {
              fn(detail);
              emit(this, e, { detail });
            };
            if (this.triggerUpdate) {
              this.triggerUpdate();
            }
          }
        });
      });
      return super.observedAttributes;
    }
    __events = {};
  };
export const Component = withEvents(withComponent(withRenderer()));

Für eine neue Webkomponente wird zunächst ein Use-Case definiert. In diesem Fall entwickeln wir eine Komponente, die Wetterdaten von OpenWeatherMap abruft und anzeigt. Die Komponente soll später mit dem Tag weather-component genutzt werden können. Per Attribut soll die Stadt angegeben werden, zu der die Wetterdaten gehören.

Zunächst wird eine neue, leere Komponente definiert.

// src/weather-component.js
import { props } from „skatejs/dist/esnext“;
import { html } from „lit-html/lib/lit-extended“;
import { Component } from „./util“;
export default class extends Component {
    static state = {
        city: {}
    }
    updateState(state) {
        this.state = state;
    }
    render() {
        return html`
        &ltdiv>Ich bin die Weather Component&lt/div>
        `;
    }
}

Es wird eine neue Klasse erstellt, die von der Basisklasse erbt, die zuvor als Mixin angelegt wurde. Ebenso wird das HTML-­Objekt importiert, das den Renderer von LitHTML repräsentiert. Die Render-Funktion ist eine Standardfunktion, die als Rück­gabe immer ein TemplateResult hat, sprich: das entsprechende ­Template, das im DOM gerendert werden soll.

Um den aktuellen Stand der Komponente zu betrachten, ergänzen wir das Projekt noch um eine index.html, die die Komponente nutzt.

< !-- index.html -->
< script src=“./dist/main.js“>

Um die Nutzung komplett zu machen, wird ein Einstiegsskript benötigt, das die Komponentenklasse als Custom-Element ­definiert.

// src/index.js
import ‚@webcomponents/webcomponentsjs‘;
import WeatherComponent from „./weather-component“;
customElements.define(„weather-component“, WeatherComponent);

Mit einem einfachen npm start lässt sich ein Development-­Server starten, der dann die Komponente im Browser darstellt.

Über die API landen die Wetterdaten in der Browser-Konsole und können dann im Frontend dargestellt werden. (Screenshot: Aaron Czichon)

Über die API landen die Wetterdaten in der Browser-Konsole und können dann im Frontend dargestellt werden. (Screenshot: Aaron Czichon)

Nachdem die Grundlagen für eine Web Component gelegt sind, sollen nun echte Daten benutzt werden. Zunächst muss die API von OpenWeatherMap angebunden werden. Um ohne zusätzliche JavaScript-Packages auszukommen, können wir hierzu die Fetch-API nutzen. Die Web-Component-Spezifikation sieht vor, eine sogenannte connectedCallback-Funktion aufzurufen, sobald eine Komponente an ein DOM-Element angehängt wird. Diese ­Lifecycle-Funktion kann nun genutzt werden, um die Daten von der Wetter-API aufzurufen.

// src/weather-component.js
connectedCallback() {
        fetch(‚https://api.openweathermap.org/data/2.5/weather?q=Heidenheim&APPID=API_TOKEN‘)
            .then(res => res.json())
            .then(data => console.log(data));
 }

Wird nun die Anwendung im Browser erneut geladen, finden wir die Wetterdaten der OpenWeatherMap in der Browser-Konsole (siehe Abbildung links).

Da die Komponente später in unterschiedlichen Applikationen genutzt werden soll, darf der Ort für die Wetterdaten nicht festgelegt sein. Daher können wir Propertys (Attribute) für eine Komponente definieren, die von außen in die Komponente gegeben werden können.

Bitte beachte unsere Community-Richtlinien

Wir freuen uns über kontroverse Diskussionen, die gerne auch mal hitzig geführt werden dürfen. Beleidigende, grob anstößige, rassistische und strafrechtlich relevante Äußerungen und Beiträge tolerieren wir nicht. Bitte achte darauf, dass du keine Texte veröffentlichst, für die du keine ausdrückliche Erlaubnis des Urhebers hast. Ebenfalls nicht erlaubt ist der Missbrauch der Webangebote unter t3n.de als Werbeplattform. Die Nennung von Produktnamen, Herstellern, Dienstleistern und Websites ist nur dann zulässig, wenn damit nicht vorrangig der Zweck der Werbung verfolgt wird. Wir behalten uns vor, Beiträge, die diese Regeln verletzen, zu löschen und Accounts zeitweilig oder auf Dauer zu sperren.

Trotz all dieser notwendigen Regeln: Diskutiere kontrovers, sage anderen deine Meinung, trage mit weiterführenden Informationen zum Wissensaustausch bei, aber bleibe dabei fair und respektiere die Meinung anderer. Wir wünschen Dir viel Spaß mit den Webangeboten von t3n und freuen uns auf spannende Beiträge.

Dein t3n-Team

Schreib den ersten Kommentar!

Melde dich mit deinem t3n Account an oder fülle die unteren Felder aus.

Bitte schalte deinen Adblocker für t3n.de aus!

Hey du! Schön, dass du hier bist. 😊

Bitte schalte deinen Adblocker für t3n.de aus, um diesen Artikel zu lesen.

Wir sind ein unabhängiger Publisher mit einem Team bestehend aus 65 fantastischen Menschen, aber ohne riesigen Konzern im Rücken. Banner und ähnliche Werbemittel sind für unsere Finanzierung sehr wichtig.

Danke für deine Unterstützung.

Digitales High Five,
Stephan Dörner (Chefredakteur t3n.de) & das gesamte t3n-Team

Anleitung zur Deaktivierung