Progressive Web Apps, kurz PWA, sorgen dafür, dass sich Webapplikationen an native Applikationen annähern und das nicht nur auf mobilen Endgeräten, sondern auf allen Plattformen. Die grundlegenden Technologien, wie beispielsweise Service Worker, werden vom Browser zur Verfügung gestellt. Eine PWA ist jedoch mehr als nur eine Applikation, die eine Reihe moderner Technologien nutzt. Der Grundgedanke, der hinter einer PWA steht, ist, dass sie auf allen Plattformen lauffähig ist und überall die wichtigsten Informationen und Interaktionsmöglichkeiten bietet. Je nachdem, wie modern die Plattform ist, auf der die PWA ausgeführt wird, kommen Features wie Offline-Fähigkeit, Installierbarkeit oder der Empfang von Push-Benachrichtigungen hinzu. Moderne Frameworks liefern mittlerweile zumindest eine rudimentäre Unterstützung für PWAs mit. In den folgenden Abschnitten erfahren Sie, wie Sie mit wenigen Schritten Ihre React-Applikation in eine PWA verwandeln können.

Die Entwicklung einer PWA bedeutet in erster Linie ein Umdenken für Entwickler. Einige Muster, die sich bei der Entwicklung von Webapplikationen etabliert haben, gelten nicht mehr oder müssen angepasst werden. Allen voran ist hier die Offline´-Fähigkeit von Applikationen zu nennen. Mit den Möglichkeiten, die moderne Browser bieten, können Applikationen auch ohne oder mit einer schlechten Internetverbindung eingesetzt werden. Die Entwickler von Google haben zum Thema PWA eine Reihe von Blogartikeln verfasst. Als Einstieg eignet sich der Artikel „Your First Progressive Web App“. Hier finden Sie eine Liste von zehn Punkten, die eine PWA ausmachen. Das sind im Einzelnen:

  • Progressive: Die Applikation ist auf jedem System funktionsfähig, wenn auch mit einem eingeschränkten Funktionsumfang.
  • Responsive: Unterschiedliche Geräte bedeuten für eine PWA auch, dass sie sich an die Anzeige- und Bedienungsbedingungen des Geräts anpassen muss.
  • Connectivity independent: Eine PWA muss unabhängig von einer bestehenden Internetverbindung lauffähig sein.
  • App-like: Die Übergänge von einer PWA zu einer nativen App sind fließend. Im besten Fall sind beide kaum voneinander zu unterscheiden.
  • Fresh: Eine PWA ist stets auf dem neuesten Stand.
  • Safe: Die Kommunikation zwischen der PWA und dem Server erfolgt stets verschlüsselt.
  • Discoverable: Bei der Entwicklung einer PWA wird dafür gesorgt, dass die Applikation durch Suchmaschinen indexiert und so durch Benutzer aufgefunden werden kann.
  • Re-engageable: Die PWA ist in der Lage, den Benutzer über Ereignisse zu informieren und ihn so zurück in die Applikation zu holen.
  • Installable: Eine PWA kann, ähnlich wie eine native App, auf dem System installiert werden.
  • Linkable: PWAs sind Webapplikationen und als solche über eine URL erreichbar, die als Bookmark gespeichert oder über Kommunikationswege wie E-Mail geteilt werden kann.

Neben dieser Beschreibung gibt es verschiedene Checklisten. Eine der am häufigsten verwendeten ist die von Google, die unter developers.google.com verfügbar ist. Sie enthält die wichtigsten Themenbereiche und gibt zahlreiche Hinweise, welche Aspekte Sie in Ihrer Applikation überprüfen können und wie sich Probleme mit den einzelnen Punkten beheben lassen.

Arbeiten Sie mit React, übernimmt die Bibliothek die ersten Schritte in Richtung PWA für Sie, wenn Sie Ihre Applikation mit dem Werkzeug Create-React-App erzeugen. Das Kommandozeilenwerkzeug registriert einen Service Worker und erzeugt eine Web App Manifest-Datei für Sie. Beide weisen eine Standardkonfiguration auf, die Sie an verschiedenen Stellen anpassen sollten. In den folgenden Abschnitten sehen Sie, wo Sie Ihre Applikation konkret anpassen müssen, um die zehn Merkmale einer PWA zu erfüllen.

Progressive

Damit Ihre PWA auf jedem System funktioniert, müssen Sie dafür sorgen, dass die Verwendung moderner Browserschnittstellen in älteren Browsern nicht zu Fehlern führt. Dies erreichen Sie durch Featuredetection, also die Überprüfung, ob die gewünschte Schnittstelle auch wirklich vorhanden ist, bevor Sie sie verwenden. Ein Beispiel für eine solche Featuredetection finden Sie bei der Registrierung des Service Workers in der Datei serviceWorker.js im src-Verzeichnis Ihrer Applikation.

export function unregister() {
if('serviceWorker'in navigator)
navigator.serviceWorker.ready.then(registration => {
registration.register();
    });
  }
}

Codebeispiel: Registrierung eines Service Workers

Eine solche Prüfung sollten Sie für jede Schnittstelle durchführen, die Sie in Ihrer Applikation verwenden. Eine gute Anlaufstelle, um herauszufinden, für welche APIs dies erforderlich ist, ist die Webseite caniuse.com. Hier finden Sie eine detaillierte Auflistung der Browserunterstützung einzelner Features. Sobald eine Schnittstelle von allen Browsern unterstützt wird, kann die Featuredetection entfallen.

Bei der Implementierung sollten Sie stets darauf achten, dass sämtliche relevante Features Ihrer Applikation verfügbar sind. Das gilt nicht nur für technische Schnittstellen, sondern auch für den Inhalt. Hier gilt es abzuwägen, wie weit Sie hier gehen wollen. Im Extremfall muss Ihre Applikation auch mit abgeschaltetem JavaScript noch funktionieren. Das bedeutet, dass Ihnen hier nur die Möglichkeiten von reinem HTML und CSS zur Verfügung stehen. In diesem Fall müssen Sie beispielsweise zu serverseitigem Rendering greifen, das ebenfalls von React unterstützt wird. In der Regel wird bei einer Single Page-Applikation ein leerer Container ausgeliefert, in den die Applikation gerendert wird. Bei serverseitigem Rendering übernimmt diese Aufgabe der Server und liefert bereits eine vorbereitete Version der Applikation aus.

Eine abgeschwächte Variante besteht darin, dass Sie Ihren Benutzern zumindest eine Warnmeldung anzeigen, dass die Applikation nur mit aktiviertem JavaScript funktioniert, sodass sie nicht vor einer leeren Seite stehen.

Responsive

Die Anforderung, dass eine PWA responsive sein soll, bedeutet, dass sie sich an die Gegebenheiten der jeweiligen Umgebung anpasst. Das bedeutet in erster Linie die Elemente der Anzeige so anzuordnen, dass sie auf der Anzeigefläche optimal zur Geltung kommen. Auch die Bedienbarkeit der verschiedenen Kontrollelemente spielt eine große Rolle. Gehen Sie davon aus, dass Ihre Applikation auf einem Mobilgerät genutzt wird, müssen alle Elemente, mit denen ein Benutzer interagiert, deutlich größer sein als auf einem Desktop, da der Benutzer diese in der Regel mit den Fingern über Touch-Gesten bedient. Auf regulären Computern kann der Benutzer auf eine Maus oder ein Touchpad zurückgreifen, das eine wesentlich feinere Steuerung erlaubt. Hier fühlen sich übergroße Kontrollelemente eher störend an.

Bei der Implementierung Ihrer Applikation benötigen Sie zwar ein Konzept und ein eigenes Design für Ihre Applikation. Jedoch gibt es zahlreiche Ressourcen, die Ihnen bei dieser Aufgabe helfen. Allen voran ist hier das Material Design von Google zu nennen. Hier wird beschrieben, wie eine Oberfläche für mobile Endgeräte optimalerweise gestaltet werden sollte. Diese Regeln und Best Practices werden für React im Projekt Material-UI in konkrete Komponenten umgesetzt. Neben den standardisierten Formularelementen existieren zahlreiche weitere hilfreiche Komponenten wie Menüs, Listen und Tabellen. Außerdem können Sie das Material Grid System einbinden, das Ihnen die flexible Platzierung von Elementen in einem Grid erlaubt, das auf verschiedene Breakpoints, also Fenstergrößen, reagieren kann.

Für die Verwendung von Material-UI laden Sie das Paket über Ihren Paketmanager herunter. Anschließend binden Sie die Basisschriftarten ein und können dann die Komponenten der Bibliothek wie normale React Components in Ihrer Applikation verwenden.

Abbildung - Codebeispiel eines Grids

Codebeispiel eines Grids

Abbildung_Beispiel einer Grid-Konfiguration mit Material-UI

Beispiel einer Grid-Konfiguration mit Material-UI

Connectivity Independent

Damit eine Web-Applikation wirklich mit nativen Apps in Konkurrenz treten kann, muss sie unabhängig von einer bestehenden Internetverbindung werden. Dieses Ziel wird bereits seit langer Zeit verfolgt. Bis vor Kurzem gab es jedoch noch keine wirklich zufriedenstellende Lösung für dieses Problem. Mit der Einführung von Service Workern und in Kombination mit lokalen Speicherlösungen des Browsers wie IndexedDB ist es mittlerweile jedoch möglich, teilweise oder auch vollständig offlinefähige Applikationen umzusetzen.

Beginnen Sie die Entwicklung Ihrer React-Applikation mit Create-React-App, wird Ihnen die Datei serviceWorker.js erzeugt. Diese ist dahingehend vorbereitet, dass ein Service Worker für Ihre Applikation registriert wird. Dieses Feature ist jedoch standardmäßig deaktiviert, sodass Sie die Registrierung im Code zunächst aktivieren müssen.

Abbildung_Debuggingmöglichkeit eines Service Workers im Browser

Debuggingmöglichkeit eines Service Workers im Browser

Sobald der Service Worker aktiviert ist, wirkt er wie ein Proxy zwischen Client und Server und ist in der Lage, sämtliche Anfragen des Clients abzufangen und sie direkt lokal zu beantworten. Die Anfragen verlassen den Client also in diesem Fall nicht. Das Caching der Anfragen ist lediglich für die statischen Assets der Applikation wie Bilder, HTML-, JavaScript- und CSS-Dateien. Dynamische Anfragen an Backend-APIs werden nicht abgefangen.

Für den Umgang  mit dem lokalen Cache gibt es verschiedene Strategien von online-first, bei der zunächst der Server angefragt wird und der Cache erst verwendet wird, wenn der Server nicht antwortet, bis hin zu Cache-first, wo zunächst nach einer lokalen Version im Cache gesucht wird und der Server erst befragt wird, wenn diese nicht gefunden wurde.

In der Standardkonfiguration des Service Workers wird die Cache-first-Strategie verwendet. Das workbox-webpack-plugin sorgt dafür, dass die Dateien im Cache bei jedem neuen Release Ihrer Applikation aktualisiert werden.

Der Einsatz von Service Workern ist jedoch nur ein erster Schritt in Richtung der Verbindungsunabhängigkeit. Nachdem immer noch sämtliche dynamischen Anfragen direkt an den Server gerichtet werden, ist Ihre Applikation mit dieser Konfiguration nicht offlinefähig. Dieses Problem lässt sich lösen, indem Sie das Konzept der Applikationsentwicklung ändern: weg von online-first hin zu offline-first. Dieses Konzept sieht die Abwesenheit einer Verbindung nicht als Fehler-, sondern als Standardfall an. Erzeugt Ihr Benutzer Daten innerhalb der Applikation, werden diese in der IndexedDB des Browsers vorgehalten und synchronisiert, sobald eine Verbindung zum Server besteht. Ähnliches gilt für die umgekehrte Richtung: War die Kommunikation mit dem Server erfolgreich, werden die erhaltenen Informationen lokal zwischengespeichert, damit sie, im Falle eines Verbindungsabbruchs, zwar potenziell veraltet, aber dennoch benutzbar vorhanden sind.


const updateTodoEpic = (action$) =>
  action$.pipe(
    ofType(UPDATE_TODO),
    mergeMap((action) => {
      const promises = [];
      if (navigator.onLine) {
        const fetchPromise = fetch(`/todos/${action.payload.id}`, {
          body: JSON.stringify(action.payload),
          headers: { 'Content-Type': 'application/json' },
          method: 'PUT',
        });
        promises.push(fetchPromise);
      }
      promises.push(db.todos.update(action.payload.id, action.payload));
      return from(Promise.all(promises)).pipe(
        mergeMap(response => from(response.json())),
        mergeMap(response =>
          of(response).pipe(map((todo) => updateTodoSuccessAction(todo))),
        ),
      );
    }),
  );

Codebeispiel: Speichern der Daten einer Applikation mit Redux-Observable auf einem Server und lokal in der IndexedDB mit Dexie.js

Diese Vorgehensweise erfordert jedoch, dass Ihre Applikation in der Lage ist, mit Konflikten umzugehen. Diese entstehen, wenn zwei Benutzer zur gleichen Zeit bestimmte Ressourcen manipulieren. Erfolgt eine dieser Manipulationen online und die andere im offline-Zustand, kann der Konflikt nicht sofort aufgelöst werden. Mögliche Lösungsszenarien sind in diesem Fall beispielsweise Last-Write-Wins, wobei die letzte Schreiboperation die vorherige einfach überschreibt, oder Sie lassen den Benutzer den Konflikt selbst auflösen, sobald Sie ihn erkannt haben, indem Sie die beiden, sich widersprechenden Versionen anzeigen und den Benutzer die korrekte auswählen lassen.

Das Verhalten des Service Workers Ihrer Applikation können Sie mit workbox , einem Open Source-Werkzeug zur Konfiguration von Service Workern, noch weiter anpassen.

App-like

Ist Ihre Applikation erst einmal offlinefähig, gilt es die Unterschiede zu nativen Apps auch in der grafischen Oberfläche verschwinden zu lassen. Dies erreichen Sie zum einen, indem Sie die Gestaltung der Oberfläche an die jeweilige Umgebung anpassen. Achten Sie hier jedoch auch darauf, dass Sie zwar einen mobile-first Ansatz verfolgen sollten, die Darstellung auf normalen Computern jedoch nicht völlig aus den Augen verlieren sollten. Ein zu starker Fokus auf mobile Endgeräte kann die User Experience auf dem Desktop erheblich verschlechtern.

Abgesehen von den Kontrollelementen, die Sie über Bibliotheken wie Material-UI und eigenes CSS stylen können, sollten Sie auch dafür sorgen, dass der Benutzer der Applikation nicht ansieht, dass Sie im Browser ausgeführt wird. Um dies zu erreichen, passen Sie das Web App Manifest an. Dieses finden Sie in der Datei manifest.json im public-Verzeichnis Ihrer Applikation. Für die Darstellung der Applikation ist hier besonders die Eigenschaft display interessant. Der Standardwert ist „standalone“. In diesem Fall wird die Applikation, wenn sie direkt gestartet wird, in einem neuen Browserfenster, jedoch ohne die üblichen Browser-Controls ausgeführt. Weitere mögliche Werte sind „browser“, wobei der reguläre Browser angezeigt wird, oder „fullscreen“, bei dem die Applikation im Vollbildmodus angezeigt wird und die Kontrollelemente des Browsers ausgeblendet werden.


{
  …
  "display": "standalone",
  …
}

Codebeispiel: Auszug aus der manifest.json

Fresh

Die Eigenschaft “Fresh” bedeutet im Kontext von PWAs, dass einem Benutzer stets die neueste Version der Applikation zur Verfügung steht. Dies ist einerseits durch die Tatsache gegeben, dass es sich bei einer PWA zunächst um eine normale Web-Applikation handelt. Ist der Service Worker aktiviert, sorgt dessen Konfiguration dafür, dass die Inhalte aktualisiert werden. Für den aktuellen Stand der Daten der Applikation müssen Sie innerhalb der Applikationslogik selbst sorgen, wobei Ihnen hier auch wieder die verschiedenen, bereits erwähnten Caching-Strategien zur Verfügung stehen.

Die Background Sync-API erleichtert die Aktualisierung der Daten zusätzlich. Diese realtiv neue Schnittstelle, die auch noch nicht von allen Browsern unterstützt wird, sorgt dafür, dass die Synchronisierung zwischen Client und Server verzögert werden kann, bis eine stabile Internetverbindung besteht. Bei der Verwendung dieser Schnittstelle sollten Sie auch wieder nach den Regeln des progressive Enhancements vorgehen und prüfen, ob das Feature im aktuellen Kontext zur Verfügung steht.

Safe

Die Kommunikation über HTTPS hat sich mittlerweile zum Standard für Web-Applikationen etabliert. Einige Schnittstellen wie beispielsweise die Payment Request API sind nur verfügbar, wenn die Applikation über eine verschlüsselte Verbindung ausgeliefert wurde. Moderne Browser markieren unverschlüsselte Applikationen zusätzlich als potenziell unsicher, sodass Sie auch aus einer Marketing-Perspektive Verschlüsselung einsetzen sollten.

Discoverable

Die beste PWA nützt nichts, wenn Ihre Benutzer diese nicht auffinden können. Das Discoverable-Kriterium spielt genau auf diese Tatsache an. Eine PWA sollte als solche kenntlich sein. Das Vorhandensein eines registrierten Service Workers und eines Web App Manifests bilden die Grundzüge hierfür.

Suchmaschinen wie Bing von Microsoft indexieren PWAs gesondert. Nach einer Prüfung seitens des Suchmaschinenbetreibers können sie in den Microsoft Store aufgenommen werden und als reguläre App installiert werden. Eine so installierte App hat zusätzliche Berechtigungen auf dem System.

Re-engageable

In Edge, Chrome und Firefox steht Ihnen die Push API zur Verfügung. Über diese sind Sie in der Lage, einem Client aktiv eine Nachricht zu senden, auch wenn die Applikation gerade nicht im Vordergrund ausgeführt wird. Es ist grundsätzlich nicht möglich, direkt Nachrichten an einen Browser zu senden. Hierfür benötigen Sie einen zusätzlichen Dienstanbieter, bei dem sich der Browser registriert und über den die Nachrichten weitergeleitet werden. Die meisten dieser Dienste stehen in einem gewissen Umfang kostenlos zur Verfügung.

Zusätzlich gibt es Anbieter, die die verschiedenen Dienste bündeln und eine Schnittstelle für mehrere Endpunkte bieten.

Auch bei dieser Funktionalität sollten Sie prüfen, ob die Funktionalität im Browser zur Verfügung steht. Achten Sie außerdem darauf, es beim Versand von Nachrichten nicht zu übertreiben, da dies Ihre Benutzer schnell verärgern kann und im schlimmsten Fall zur Abwanderung von Benutzern führen kann.

Installable

Mit dem bereits erwähnten Web App Manifest können Sie eine PWA auf Ihrem System wie eine native App installieren. Das Manifest enthält die erforderlichen Informationen wie beispielsweise die display-Angabe, wie die Applikation dargestellt werden soll oder Informationen zu den zu verwendenden Icons, dem Titel oder der Beschreibung der Applikation. Sie können aus Ihrer Applikation den Benutzer zur Installation auffordern oder es dem Benutzer überlassen diese selbstständig zu installieren.

Abbildung_Anzeige der Manifestdatei im Browser

Anzeige der Manifestdatei im Browser

Linkable

Als reguläre Web-Applikation kann Ihre PWA über einen Hyperlink adressiert werden. Nutzen Sie den react-router ist auch die Navigation innerhalb der Applikation über URL-Pfade möglich. So kann ein Benutzer direkt zu einem bestimmten Zustand der Applikation springen, diesen als Bookmark speichern oder den Link an einen Freund schicken und ihn so teilen.

Fazit

PWAs stellen eine Erweiterung regulärer Web-Applikationen dar. Eine PWA kann in allen Umgebungen ausgeführt werden und passt sich an diese an. Je moderner ein Browser ist, desto mehr Komfortfeatures kann er einem Benutzer bieten. Diese reichen von der Installierbarkeit einer Applikation über die Offlinefähigkeit bis hin zum Versand von Push-Nachrichten, falls ein wichtiges Ereignis in der Applikation aufgetreten ist.

AbbildungAusführung von Lighthouse im Browser

Ausführung von Lighthouse im Browser

Zahlreiche Anbieter, allen voran Google, stellen Ihnen Dokumentation und Hilfsmittel zur Verbesserung von PWAs zur Verfügung. Eines der bekanntesten Werkzeuge aus diesem Bereich ist Lighthouse, ein Werkzeug zur Überprüfung, wie viel PWA in Ihrer Applikation steckt.

Sebastian Springer

Sebastian Springer

Sebastian Springer ist JavaScript-Entwickler bei Maiborn Wolff in München und beschäftigt sich vor allem mit der Architektur von client- und serverseitigem JavaScript. Er ist Berater und Dozent für JavaScript und vermittelt sein Wissen regelmäßig auf nationalen und internationalen Konferenzen.
Sebastian Springer

Letzte Artikel von Sebastian Springer (Alle anzeigen)

2 thoughts on “Progressive Web Apps mit React

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.

Die von Ihnen hier erhobenen Daten werden von der Host Europe GmbH zur Veröffentlichung Ihres Beitrags in diesem Blog verarbeitet. Weitere Informationen entnehmen Sie bitte folgendem Link: www.hosteurope.de/AGB/Datenschutzerklaerung/