Cross-Plattform-Entwicklung mit Ionic 4, Stencil und Capacitor, Teil 2

Capacitor und Stencil sind zwei Tools, die Entwicklern in der neuen Ionic-Version das Leben einfacher machen sollen und auch eigenständig einsetzbar sind.

In Pocket speichern vorlesen Druckansicht
Cross-Plattform-Entwicklung mit Ionic 4, Stencil und Capacitor (Teil 2)
Lesezeit: 11 Min.
Von
  • Norbert Frank
Inhaltsverzeichnis

Wenn eine Ionic-Anwendung nicht als Web-App, sondern als native mobile App erscheinen soll, konnte man seit der ersten Ionic-Version komfortabel eine Cordova-App für Android und iOS erzeugen. Diese Möglichkeit besteht mit Ionic 4 weiterhin, aber mit dem Projekt Capacitor ist eine Alternative hinzugekommen. Zwar vom Ionic-Team entwickelt, kann Capacitor wie Cordova auch unabhängig von Ionic zum Einsatz kommen.

Das Ionic-Team hat in der Vergangenheit einiges zu Cordova beigetragen und angekündigt, dies auch weiterhin zu tun. Aufgrund seiner langen Historie und weiten Verbreitung muss Cordova allerdings bei der Weiterentwicklung immer die Kompatibilität zu bestehenden Plug-ins und Versionen berücksichtigen. Bei einem neuen Projekt ist dass nicht erforderlich, sodass mit Capacitor eine zeitgemäße Alternative bereitsteht. Sie ist grundsätzlich ähnlich zu Cordova aufgebaut. Es wird ebenfalls der native Browser von iOS oder Android gekapselt und darin eine Webanwendung mit Schnittstellen zu nativen Gerätefunktionen ausgeführt. Auch das Plug-in-Konzept ist vergleichbar.

Mehr Infos

Artikelserie: Cross-Plattform-Entwicklung mit Ionic 4, Stencil und Capacitor

Capacitor unterscheidet sich von Cordova vor allem darin, dass es die nativen Build-Tools der jeweiligen Plattform stärker einbindet. Cordova bringt eigene Build-Tools mit, die das komplette Erzeugen der nativen App übernehmen. Dazu verwendet Cordova zwar die offiziellen SDKs der jeweiligen Plattform, hat aber den Anspruch, den Vorgang vollständig zu automatisieren. Das führt dazu, dass man jede Einstellung des nativen Projekts in der Cordova-Konfiguration vornehmen muss, weil sie ansonsten beim nächsten Build überschrieben werden. Auch muss man Cordova laufend an neue Versionen anpassen.

Capacitor geht einen anderen Weg, indem es die nativen Entwicklungsumgebungen integriert. Dazu erzeugt das CLI nur einmalig ein natives Projekt, das Entwickler dann mit XCode oder Android Studio weiter verwalten können. Capacitor sorgt lediglich dafür, die Webressourcen bei Änderungen in das native Projekt zu kopieren, lässt aber alle anderen Einstellungen unverändert. Das bringt mehrere Vorteile: Entwickler nativer Apps finden sich direkt zurecht, die offizielle Dokumentation ist auch für Capacitor-Projekte gültig und Capacitor ist leichtgewichtiger und flexibler.

Natürlich ist Capacitor für den Einsatz mit Ionic optimiert, aber auch für beliebige Webanwendungen einsetzbar. Als Zielplattform werden neben Android und iOS auch Electron und Progressive Web Apps (PWA) unterstützt. Die PWA-Unterstützung bedeutet, dass die Capacitor-Plug-ins – sofern technisch möglich – die Browser-API als Alternative zu nativen APIs nutzen. Auf diese Weise kann man zum Beispiel die Kamera in einer Web-App mit der gleichen API verwenden. Ein weiterer Unterschied zwischen Capacitor und Cordova ist, dass alle Plug-ins direkt zum App-Start zur Verfügung stehen und die App nicht auf ein deviceready-Event warten muss.

Capacitor bringt einige Plug-ins mit und es gibt zusätzliche Community-Plug-ins. Das Angebot ist bei dem noch jungen Projekt allerdings noch deutlich kleiner als bei Cordova, wächst aber ständig. Allerdings kann Capacitor auch Cordova-Plug-ins ausführen, sodass viele Cordova-Plug-ins auch problemlos mit Capacitor nutzbar sind. Die Capacitor-Dokumentation enthält eine Liste von inkompatiblen Plug-ins, aber die Mehrheit der Cordova-Plug-ins ist direkt einsetzbar. Das bedeutet, dass auch Ionic-Native-Plug-ins funktionieren.

Ionic-Native ist ein weiteres Projekt des Ionic-Teams und umfasst eine große Anzahl von Wrappern für bekannte Cordova-Plug-ins. Die Wrapper ergänzen Typescript-Informationen und überführen die häufig Callback-basierten APIs der Plug-ins in eine Promise-basierte API, was die Nutzung vereinfacht. Für den Einsatz eines Ionic-Native-Plug-ins müssen Nutzer immer den Wrapper und zusätzlich das Plug-in selbst installieren. Wenn das Plug-in kompatibel zu Capacitor ist, kann man auch den Ionic-Native-Wrapper mit Capacitor einsetzen.

Derzeit unterscheiden sich Capacitor und Cordova also überwiegend in der Vorgehensweise und weniger darin, dass Capacitor grundsätzlich neue technische Möglichkeiten bietet oder einen deutlichen Performance-Vorteil hätte. Von daher muss man für bestehende Projekte abwägen, ob eine Umstellung sinnvoll ist. Man wird sehen, wie sich das Projekt in der Zukunft entwickelt. Angedacht ist, eine bessere Unterstützung zur Einbettung in bestehende native Applikationen zu schaffen. Auch überlegt das Ionic-Team, einen generischen Wrapper für native SDKs zu entwickeln, um deren Funktionen aus JavaScript heraus direkt nutzen zu können und die Abhängigkeit zu spezialisierten Plug-ins zu verringern.

Stencil ist ein Compiler für Web Components und ein weiteres Tool, das das Ionic-Team entwickelt. Es ist sehr mächtig und vielseitig und daher kann es zunächst schwer fallen, es einzuordnen. Während der Entwicklung von Ionic 4 kam der Bedarf auf, allgemeine Funktionsanforderungen für die Ionic-Komponenten generisch zu lösen, anstatt in jeder Komponente individuell. Die Web-Components-Spezifikation ist zwar die Basis von allem, aber um viele Aspekte muss man sich selber kümmern, was aufwändig und umständlich ist. Als Antwort darauf ist Stencil entstanden.

Stencil bietet eine wesentlich mächtigere und komfortablere API als die native Web-Components-API der Browser. Zu den Funktionen gehört der Einsatz von JSX, TypeScript, Data-Binding, automatisches Re-Rendern wenn sich Properties ändern, Nutzung eines Virtual DOM und weiteres mehr. Stencil erreicht das nicht durch eine Runtime-Library, sondern indem die Funktionen in die Komponenten direkt integriert sind. Da Stencil ein Compiler ist, benötigt es zur Laufzeit keine zusätzliche Library und die kompilierten Komponenten sind für sich lauffähig. Das Konzept ist vergleichbar mit dem vom Framework Svelte.

Das Ionic-Team nutzt Stencil, um die Ionic-Komponenten zu entwickeln und zu kompilieren. Um die Komponenten zu verwenden, werden keine Kenntnisse von Stencil benötigt. Stencil steht als Open-Source-Tool zur Verfügung und kann auch für eigene Entwicklungen dienen. Dabei kann man zwei Szenarien unterscheiden:

  1. Entwicklung von Komponenten oder Komponenten-Libraries
  2. Entwicklung von Applikationen

Im ersten Fall wird Stencil für die Entwicklung von eigenständigen UI-Komponenten genutzt, ganz so wie es das Ionic-Team für die Komponenten macht. Da die resultierenden Web Components nicht an ein Frontend-Framework gebunden sind, ergeben sich für die eigenen Komponenten die gleichen Vorteile wie für Ionic selbst, nämlich dass sie flexibel in verschiedene Frameworks eingebunden werden können. Gerade für große Unternehmen mit einer oft heterogenen IT-Landschaft kann das ein entscheidender Vorteil sein, da generische UI-Komponenten unternehmensweit bereitgestellt werden können, ohne dass man sich auf ein durchgängig eingesetztes Frontend-Framework einigen müsste.

Das folgende Listing zeigt ein Beispiel einer Stencil-Komponente:

import { Component, Prop, State, h, Listen } from "@stencil/core";

@Component({
tag: "app-home",
styleUrl: "app-home.css"
})
export class AppHome {
@State() username = "Unbekannte(r)";

@Prop({ connect: "ion-modal-controller" })
modalCtrl: HTMLIonModalControllerElement;

@Listen("ionModalDidDismiss", { target: "body" })
modalDidDismiss(event: CustomEvent) {
if (event) {
if (event.detail.data && event.detail.data.username) {
this.username = event.detail.data.username;
}
}
}

async openEditModal() {
const modal = await this.modalCtrl.create({
component: "user-edit",
componentProps: {
username: this.username
}
});
await modal.present();
}

render() {
return [
<ion-header>
<ion-toolbar>
<ion-title>Hallo Ionic</ion-title>
</ion-toolbar>
</ion-header>,

<ion-content class="ion-padding">
<ion-card>
<ion-item>
<ion-icon name="logo-ionic" slot="start"></ion-icon>
<ion-label>
Hallo {this.username}. Schön dich kennenzulernen!
</ion-label>
<ion-button
fill="outline"
slot="end"
onClick={() => this.openEditModal()}
>
Namen eingeben
</ion-button>
</ion-item>

<ion-card-content>
Gib deinen Namen ein, um von Ionic begrüßt zu werden!
</ion-card-content>
</ion-card>
</ion-content>
];
}
}

Die Komponente nutzt Ionic-Komponenten und erzeugt eine Seite mit einem Header und einem Content-Bereich. Dort wird in einem Label der Wert von username gerendert und über einen Button kann man einen modalen Dialog zur Eingabe des Namens öffnen.

In dem Beispiel kommen mehrere TypeScript-Dekoratoren zum Einsatz:

  • @Component(): definiert die Web Component.
  • [/code]@Prop()[/code]: deklariert einen Wert, der als Attribut an die Komponente übergeben und automatisch auf Änderungen überwacht wird.
  • @State(): definiert eine interne Variable, die bei Änderungen automatisch die Render-Methode ausführt.
  • @Listen(): definiert einen Event-Listener. Im Beispiel wird beim Schließen des modalen Dialogs durch das Event ionModalDidDismiss der Rückgabewert verarbeitet.
  • @Method(): definiert eine öffentliche Methode der Web Component.

Weiterhin gibt es eine Render-Methode, in der JSX zum Einsatz kommt. Wie zu sehen ist, ist die Komponente vergleichbar zu Komponenten in Angular, React oder Vue.js. Aus dieser Definition erzeugt Stencil ein autark lauffähiges Artefakt ohne externe Abhängigkeiten.

Stencil kann aber auch zum Erstellen ganzer Applikationen dienen – und bietet daher eine Alternative zu anderen Frontend-Frameworks. Stencil positioniert sich allerdings nicht als Ersatz, sondern eher als zusätzliche Möglichkeit. Moderne Frameworks erlauben es, Komponenten zu definieren und zu strukturieren, sorgen für effizientes Rendering, Data-Binding zwischen DOM und Modell und bringen eine Komponenten-API mit. All das kann Stencil auch bieten, nutzt dazu jedoch nicht eine Runtime-Library, sondern erweitert die native Browser-API der Custom Elements um einige Funktionen, die der Compiler direkt in die Komponenten integriert.

Weitere Aufgaben, die eine Frontend-Library typischerweise übernimmt sind Routing und State-Management. Für Stencil-Projekte können Entwickler dafür folgende Erweiterungen nutzen:

  • Stencil-Router: einfacher Router für Stencil-Projekte.
  • Ion-Router: technisch sehr ähnlich zum Stencil-Router, aber in Ionic integriert.
  • Stencil-State-Tunnel: ermöglicht die komfortable Kommunikation von Werten in einer Komponten-Hierarchie. Technisch ist der State-Tunnel vergleichbar mit der Context API von React und der Provide/Inject-Funktion von Vue.js.
  • Stencil-Redux: Integration von Redux in Stencil-Projekte.

Die vergleichsweise kleine API von Stencil ist schnell erlernbar. Stencil ist somit eine interessante Alternative für die Erstellung von kleinen und mittelgroßen Webanwendungen. Es gibt erste Praxiserfahrungen von Unternehmen, die mit Stencil nicht nur ihre UI-Komponenten sondern auch ihre Anwendungen entwickeln. Weitere Informationen bietet die geplante weitere Roadmap.

Wie im ersten Teil gezeigt, ermöglicht Ionic 4 mit generischen Web Components vielfältige Einsatzmöglichkeiten und bietet fertige Integrationen in Angular, React und Vue.js. Wenn man eine native App erstellen möchte, kann Capacitor als zeitgemäße Alternative zu Cordova dienen.
Darüber hinaus ist der vom Ionic-Team als Open Source veröffentlichte Web-Components-Compiler Stencil nicht nur für Ionic-Projekte interessant, sondern kann auch für die Entwicklung eigener UI-Libraries oder ganzer Applikationen Verwendung finden.

Ein interessantes Praxisbeispiel für den weiteren Einstieg ist die Anwendung "Ionic Conference App". Dabei handelt es sich um eine Demo-App mittlerer Komplexität, die mit Ionic in Kombination mit Angular, React, Vue.js und Stencil umgesetzt wurde.

Für das nächste Release wollen sich die Ionic-Entwickler vor allem darauf konzentrieren, das Angebot an UI-Komponenten weiter auszubauen.

Norbert Frank
ist seit 15 Jahren in der IT als Entwickler, Berater und Softwarearchitekt tätig. Er ist passionierter Full-Stack-Entwickler und JavaScript-Enthusiast bei der Lucom GmbH.
(bbo)