Titelvorschau

Erstellen einer PWA mit React

Von am 05.01.2021

Progressive Web Apps, kurz PWA, sind Web-Anwendungen, die über den Browser und nicht über eine App-Store-Installation aufgerufen werden. Sie sorgen dafür, dass sich Webapplikationen für BenutzerInnen wie native Applikationen anfühlen, sowohl auf allen mobilen Endgeräten als auch auf allen Plattformen. Die dafür notwendigen Technologien werden vom Browser zur Verfügung gestellt.

PWAs können nützliche Features von Native Apps bieten, wie die Offline-Fähigkeit, Installierbarkeit oder der Empfang von Push-Benachrichtigungen. PWAs verringern also die Lücke zwischen der User Experience in webbasierten und nativen Anwendungen.

Nennenswerte Features sind:

  • Die Möglichkeit Offline zu laufen
  • Eine hohe Performance in Relation zu reinen Webanwendungen
  • Background processing mit Serviceworkers in einem separaten Thread
  • Der Zugriff auf die Sensoren des Endgeräts
  • Die Unterstütztung von Push-Benachrichtigungen
  • Installation der App über den Browser/Hinzufügen eines Icons am Homescreen

In diesem Artikel wird erläutert, wie man mit dem leistungsfähigen Framework ReactJs eine React-App für PWAs optimieren kann. Dazu werden wir uns das allgemeine Project-Setup von React ansehen, einen ServiceWorker implementieren, kurz auch das Manifest diskutieren und zum Schluss wie wir unsere App builden und diese installieren können.

React Project-Setup

Im ersten Schritt erstellen und initialisieren wir ein neues React-Projekt. Dazu installieren wir uns über NPM das create-react-app Modul in unserem Projekt-Folder. Dieses nimmt uns schon mehrere Konfigurationen und Setup für unsere PWA ab: npm install -g create-react-app

Jetzt kannst du über den Befehl create-react-app <app_name> das Projekt erstellen lassen.Ist die Projektstruktur angelegt, führen wir unsere App aus, um zu testen ob das Projekt-Setup funktioniert hat. Dazu wechseln wir in unser neu erstelltes App-Verzeichnis und starten die Webanwendung mit npm start

Hat alles funktioniert, solltest du nun folgende Seite über deinen localhost sehen:

Serviceworker

Im nächsten Schritt schauen wir uns den Public-Folder genauer an. Hier müssen wir nun einige Konfigurationen vornehmen, dass wir unsere erstellte React-App für eine PWA optimieren. Dafür brauchen wir im ersten Schritt einen Serviceworker.

Die technische Grundlage für eine PWA bilden die Serviceworker. Ein Serviceworker ist ein Code, den dein Browser im Hintergrund verarbeitet, um die Offline-Fähigkeit für Webanwendungen zu ermöglichen. Es fängt Requests vom Netzwerk ab und verarbeitet sie als Vermittler zwischen deinem Browser und dem Netzwerk. Dieses Skript ist nur im Produktionsmodus aktiv und übernimmt also das Caching und Ausliefern der Assets der Web-App.

Um den Serviceworker zu verwenden brauchen wir in unser public/index.html im body-Tag eine Abfrage, ob der Serviceworker von dem verwendeten Browser überhaupt unterstützt wird. Wenn ja, soll dieser beim Laden registriert werden.

  <body>

    <noscript>You need to enable JavaScript to run this app.</noscript>

    <div id=”root”></div>

    <script>

      if(‘serviceWorker’ in navigator){

        window.addEventListener(‘load’, ()=>{

          navigator.serviceWorker.register(‘./serviceworker.js’)

          .then((reg)=> console.log(‘Success’, reg.scope))

          .catch((err) => console.log(‘Failure’, err));

        })

      }

    </script>   

  </body>

Diese Codezeilen ermöglichen es uns nun, einen eigenen Serviceworker zu verwenden, dazu legen wir uns das definierte Script serviceworker.js im public-Folder an.

Um das ganze zu testen, öffnen wir die Developertools im Browser. Hier haben wir die Möglichkeit unter dem Reiter „Application“ unseren Serviceworker und das Manifest (dazu später mehr) anzusehen. Wichtig dabei ist, dass wir für das Testen den „Reload“ aktivieren. Danach löschen wir den Storage und laden die Seite nochmal neu, um zu sehen, ob unsere Registrierung erfolgreich war.

Nun brauchen wir Events und Konfigurationen für unseren Serviceworker. Das ist zum Einen der Cache und die Urls die gecached werden sollen. Dabei haben wir die „normale“ index.html und eine offline.html die angezeigt werden soll, wenn keine Internetverbindung besteht.

//cache aktivieren

const CACHE_NAME = “version-1”;

const urlsToCache = [“index.html”, “offline.html”];

//das ist der serviceworker

const self = this;

Events brauchen wir drei. Das erste Event installiert unseren Serviceworker. Wir öffnen damit den Cache und fügen unsere definierten Files hinzu:

//event für die Installation des ServiceWorkers

self.addEventListener(“install”, (event)=>{

  event.waitUntil(

    caches.open(CACHE_NAME)

      .then((cache)=>{

        console.log(“Opened Cache”);

        return cache.addAll(urlsToCache);

      })

  )

})

Nun probieren wir das Ganze im Browser aus. Wir löschen unseren Browser-Storage und laden die Seite neu. Danach solltest du, wenn alles funktioniert hat, die entsprechende „Opened Cache“-Message in der Konsole sehen. Beim erneuten „Reload“ sollte die Meldung nicht mehr ausgegeben werden, da nun der Cache bereits verwendet wird.

Nun bauen wir uns einen EventListener der auf unsere Anfragen horcht. „Requests“ können beispielsweise Images oder API-Calls sein. Wenn das Holen der angefragten Ressource fehlschlägt, bedeutet das, dass wir keine Internetconnection haben und liefern die offline.html zurück.

//auf Request horchen

self.addEventListener(“fetch”, (event) => {

  // Antwort mit angeforderter Ressource

  event.respondWith(

    //Request beispielsweise ein Image oder API-Call

    caches.match(event.request)

      .then(()=> {

        return fetch(event.request)

          .catch(()=> caches.match(“offline.html”))

      })

  )

})

Im nächsten Schritt brauchen wir noch einen EventListener der uns unseren Serviceworker aktiviert.

//aktivieren des SW

self.addEventListener(“activate”, (event) => {

  const cacheWhitelist = [];

  cacheWhitelist.push(CACHE_NAME);

  event.waitUntil(

    caches.keys().then((cacheNames) => Promise.all(

      cacheNames.map((cacheName) => {

        if(!cacheWhitelist.includes(cacheName)){

          return caches.delete(cacheName);

        }

      })

    )

  ))

})

Der Serviceworker ist nun soweit fertig! Jetzt kannst du dir eine x-beliebige offline.html Seite erstellen und dann testen wir den Code. Wenn alles funktioniert hat, wird immer der aktuellste Cache herangezogen und die Offline-Seite angezeigt werden, wenn keine Internetverbindung besteht. Dazu kannst du in den Entwicklertools den Reiter „Network“ verwenden. Hier stellen wir auf Offline um und laden die Seite neu.

Das war der schwierigste Teil! Mit dem Lighthouse-Audit schauen wir uns nun an, wie gut unsere App bereits für die PWA optimiert ist. Dazu lassen wir uns den Lighthouse-Bericht erstellen. Diesen findest du im Reiter “Lighthouse” in den Entwicklertools. Achtung! – gehe sicher, dass du auch den Network-Mode wieder auf Online umgestellt hast. Mit unseren derzeitigen Konfigurationen sollte der Report für die PWA schon relativ gut aussehen.

Dank unserer Initialisierung durch create-react-app wurden uns schon Konfigurationen für das Manifest abgenommen.

Manifest

Ein Web-App-Manifest ist standardmäßig in Create-React-App enthalten und ermöglicht es jedem, die React-Anwendung auf seinem Gerät zu installieren. In React ist das Manifest ein ganz normales Json-File wo verschiedene Properties definiert werden können, wie die App auf dem Homescreen nach Installation aussehen soll. Standardmäßig sind das der Name, die Beschreibung, das App Icon, die Theme-Farbe, die Display-Settings und auch die Starturl der App, wenn sie geöffnet wird.

Create-React-App hat all diese Konfigurationen bereits für dich vordefiniert, die du ganz einfach an deine eigene React-App anpassen kannst. Wichtig dabei ist, dass du es natürlich auch in deiner index.html einbindest.

    <link rel=”manifest” href=”%PUBLIC_URL%/manifest.json” />

Eine weitere Validierung, die im Lighthouse-Audit fehlgeschlagen ist, ist das maskable icon. Maskable Icons sind ein neues Format, das sicherstellt, dass das PWA-Icon auf allen Endgeräten entsprechend passt. Auf neueren Android-Geräten erhalten PWA-Icons, die nicht dem maskierbaren Symbolformat entsprechen, einen weißen Hintergrund. Um es als „maskable“ zu liefern, geben wir ein weiteres Property „purpose“ im Icons array in unserem Manifest an:

… 

 “icons”: [

    {

      “src”: “favicon.ico”,

      “sizes”: “64×64 32×32 24×24 16×16”,

      “type”: “image/x-icon”,

      “purpose”: “any maskable”

    },

Production-Build

Eine Validierung schlägt beim Lighthouse-Audit noch fehl. Es besteht derzeit noch kein Redirect von HTTP traffic zu HTTPS. Wir müssen also unsere App noch für die „Production“ builden und deployen. Dazu führen wir den Befehl npm run build aus, der uns unsere gesamten Ressourcen unseres Projektes „bundlet“ und einen Build-Ordner erstellt.

Um nun unseren Build zu veröffentlichen und zu testen, kannst du für Testzwecke beispielsweise die Seite netlify verwenden. Nach Veröffentlichung, wenn du den Weblink nun öffnest, solltest du eine fertig optimierte React PWA haben. Dazu kannst du sicherheitshalber erneut die oben beschriebenen Tests auf der Webseite und den Lighthouse-Audit durchlaufen lassen. Zum Testen des Offline-Modus würde ich zusätzlich noch empfehlen, einmal wirklich das Internet abzuschalten.

Installieren der App

Unsere PWA ist nun fertig optimiert und nun können wir die App auch installieren. In deinem Browser siehst du ein Plus-Symbol, welches dir erlaubt, die App auf deinen Homescreen hinzuzufügen und als App auszuführen. Dasselbe funktioniert über „App installieren“ am Smartphone über Chrome. Sobald du auf Installieren klickst, wird automatisch eine Verlinkung auf deinem Desktop erstellt und die App installiert.

Fertig ist deine erste React PWA!

Tipp: Es gibt auch einen eigenen Store für Progressive Web Apps wo du deine PWA veröffentlichen kannst. Diesen findest du unter https://progressiveapp.store

Zusammenfassung

Zusammengefasst sind PWAs Apps die über den Browser aufgerufen werden, sich jedoch wie Native Apps anfühlen. Sie bieten nützliche Features von Native Apps, wie die Offline-Fähigkeit, Installierbarkeit und weisen eine weit bessere Performance als reine Webanwendungen auf. Sie verringern die Lücke zwischen der User Experience in webbasierten und nativen Anwendungen.

Zusätzlich wurde erläutert, wie eine React-App erstellt und für PWAs optimiert werden kann. Verwendet haben wir dazu create-react-app, dass uns schon ein Projekt-Setup mit Vorkonfigurationen für unsere PWAs bietet. Auch der Serviceworker war ein großes Thema, der die technische Grundlage von PWAs darstellt. Mit Serviceworker kann eine PWA Ressourcen cachen und diese zwischensgepeicherten Daten verwenden, wodurch eine bessere UX ermöglicht wird. Damit können Web-Apps dynamisch geladen werden, während man durch die App navigiert und den Datenverkehr minimiert. Zusätzlich haben wir erfahren, dass uns das Manifest Konfigurationen für den Homescreen und die Installation ermöglicht.  Mit dem Lighthouse-Audit kann man PWAs auf ihre Optimierung testen. Schlussendlich wurde erläutert, wie man am Ende die PWA “buildet” und auf dem Endgerät installiert.

Beitrag kommentieren

(*) Pflichtfeld