Comparative Web Performance evaluation of Vue & React using JSWFB

ReactJS vs VueJS

Abstract

During this period of time where, the digital world, where nearly 5 billion people are using the internet, comes the need to build a web application that is intuitive, interactive and with higher speed performance. That’s where the JavaScript Libraries and Frameworks come into the picture. In the current web development culture, ReactJS and VueJs are the most used and most loved web frameworks. They are used to develop interactive single web page applications. This paper will evaluate these frameworks regarding their performance and usage using the JS Web Framework Benchmark.

ReactJS vs VueJS
ReactJS vs VueJS
Continue reading

Neue Bildformate im Vergleich

Bilder und andere Medienelemente gelten im Internet heute als selbstverständlich. Wie aus dem HTTP Archive hervorgeht, generieren 99,9% aller Webseiten mindestens eine Anfrage für eine Bildressource und 95,9% enthalten mindestens ein <img>-Element [1]. Die restlichen 4% entfallen beispielsweise auf Favicons und Hintergrundbilder.

Für die breite Verwendung von Bildern gibt es gute Gründe: Sie transportieren Informationen schneller als Text, lockern das Layout auf und regen Nutzer zu mehr Interaktion an [2]. Wie Abbildung 1 veranschaulicht, schlägt sich dies auch im Anteil von Medienelementen an der gesamten Größe einer Webseite (Page Weight) nieder [3]. So machen Bilder, Animationen und Videos durchschnittlich zwei Drittel des gesamten Page Weights aus – und selbst im zehnten Perzentil nehmen sie noch einen Anteil von etwa 44% ein.

Continue reading

Drei Sekunden sind zu lang – Auswirkung der Ladezeit von Webseiten auf die User Experience

Warum ist es so wichtig, die optimale Ladezeit anzustreben?

Auf jemanden oder auf etwas zu waren ist uns Menschen nicht fremd. Im Schnitt verbringt jeder Mensch in seinem Leben rund ein bis zwei Jahre mit Warten. Dies kann an der Bushaltestelle, Suppermarktkasse, dem Abwarten auf die Ankunft einer Zustellung, oder die Ankunft einer geliebten Person sein. Viele Menschen erscheint das Warten auf etwas oder jemanden als lästig. Dies kann verschiedenste Gründe haben wie bspw. Langeweile, die seelische Verfassung und der allgemeine Gemütszustand, sowie Zeitdruck. Ganze Geschäftsmodelle wie das “Priority Boarding” am Flughafen beruhen darauf, dass Menschen bereit sind mehr Geld zu bezahlen, nur um nicht anstehen zu müssen. (D. Lenz 2018)

Continue reading

Automate Performance Optimization

In order to display a website as quickly as possible, performance optimization is necessary. Since manual optimization can be time-consuming and often several steps need to be performed, automating performance optimization can be a good idea. This in turn can include, for example, reporting (speed analysis of the website) and performance optimization itself (compression, code reduction, …).
This article gives an overview of where automation can be used, which tools are suitable for this and what these tools offer.

Continue reading

Progressive Web Apps – Wer braucht noch native Apps?

Progressive Web Apps sollen es ermöglichen die Vorteile des Webs und die nativer Apps zu nutzen, um so für jeden, überall und auf jedem Gerät, nutzbar zu sein. Was Progressive Web Apps eigentlich sind, welche Vor- und Nachteile sie mit sich bringen und ob sie in Zukunft native Apps komplett ersetzen können, soll in diesem Artikel beantwortet werden. 

Was sind Progressive Web Apps?

Der Name Progressive Web Apps (PWA) ist kein formeller oder offizieller Name sondern nur eine Abkürzung. Diese wurde ursprünglich von Google für das Konzept verwendet, eine flexible und anpassbare App nur mit Webtechnologien (HTML, CSS, JavaScript) zu erstellen.
Der Begriff Progressive im Namen kommt daher, dass das Konzept PWA auf der Design Philosophie Progressive Enhancement basiert.[1] Diese besagt, dass so vielen Nutzern wie möglich die grundlegende Funktionalität zur Verfügung gestellt werden soll. Mithilfe von Feature Detection wird in der Implementierung überprüft, ob der Browser mit der gewünschten Funktion umgehen kann. Falls dies nicht der Fall ist, wird eine alternative Implementierung mittels Polyfills bereitgestellt, um die fehlende Funktion mit JavaScript hinzuzufügen. Dadurch wird eine ausgezeichnete Erfahrung für voll leistungsfähige Browser ermöglicht und eine akzeptable Erfahrung für weniger leistungsfähige Browser.[2]

“These apps aren’t packaged and deployed through stores, they’re just websites that took all the right vitamins.”

Alex Russell [3]

Wie Alex Russell, der als Google Engineer das PWA Konzept mitentwickelt hat, mit seinem Zitat beschreibt, sind PWAs im Kern einfache Webanwendungen. Mithilfe von speziellen Technologien und Patterns wollen sie die Vorteile des Webs und die nativer Apps nutzen. Hierzu zählen beispielsweise die einfache Auffindbarkeit im Web oder die Möglichkeit der Offline-Nutzung nativer Apps.[1], [4]
Um eine bestmögliche Nutzererfahrung zu erzielen, die sich anfühlt wie bei einer plattformspezifischen Anwendung hat Google drei Säulen definiert, die eine PWA erfüllen sollte:

  • capable (fähig): Durch die Verwendung von modernen APIs werden Webanwendungen immer leistungsfähiger und ermöglichen die Implementierung nativer Möglichkeiten, zum Beispiel den Dateisystemzugriff oder die Mediensteuerung.
  • reliable (zuverlässig): Benutzer erwarten, dass Anwendungen immer schnell und verlässlich sind, unabhängig von der Netzwerkverbindung. Interaktionen sollten immer schnell erkannt werden und es sollte so schnell wie möglich darauf reagiert werden. Denn gerade die Geschwindigkeit ist wichtig für die UX.
  • installable (installierbar): Über den Add2Homescreen-Button sollte die PWA installierbar sein, um in einem eigenständigen Browserfenster zu laufen. Dadurch verhält sich die PWA auf der einen Seite wie eine native App. Auf der anderen Seite ändert der Nutzer seine Interaktion mit der App, da die App nun vom Homescreen oder vom Appswitcher gestartet werden kann.[4]

Aussehen und Lebenszyklus einer PWA

Der Lebenszyklus beginnt wie bei einer normalen Webseite im Browser. Durch das Anzeigen des Add2Homescreen- Buttons (im Moment nur bei Android Geräten möglich) kann der Nutzer die App zum Homescreen hinzufügen. Auf dem Homescreen wird das Appicon analog zu einer nativen App dargestellt. Öffnet man nun die App über den Homescreen, öffnet sich die PWA im Standalone- Modus und sie sieht aus wie eine native App. Außerdem wird sie, wie auch native Apps, im Appswitcher angezeigt.

Aussehen und Lebenszyklus einer PWA [3]

Wie wird aus einer Webanwendung eine PWA?

Bei Web Anwendungen ist es nicht immer direkt ersichtlich, ob es sich um eine reine Web Anwendung handelt oder um eine PWA. Damit eine Web Anwendung als PWA erkannt wird, muss sie bestimmte technische und funktionale Anforderungen erfüllen.

Technische Anforderungen

Aus technischer Sicht sollte eine Web Anwendung die folgenden drei Eigenschaften haben, um als PWA zu gelten:

HTTPS – Die Verwendung einer sicheren Netzwerkverbindung ist nicht nur Best Practice, sondern bietet auch den Vorteil, dass Nutzer der Webseite vertrauen. Zusätzlich ist eine sichere Verbindung mittels HTTPS die Voraussetzung für die Nutzung vieler Funktionen, die in PWAs verwendet werden. Hierzu zählen beispielsweise die Geolokalisierung oder auch die Verwendung eines Service Workers.[5],[7]

Service Worker – Ein Service Worker ist eine JavaScript-Datei die der Browser im Hintergrund ausführt und welche als programmierbarer Netzwerk Proxy dient. Dadurch kann bestimmt werden, wie der Browser Netzwerkanfragen und Asset-Caching behandelt. Durch die Verwendung eines Service Workers können zuverlässige und schnelle Webseiten implementiert werden, die zusätzlich Offline-Funktionalität bieten.[5]–[7]

Manifest – Das Manifest ist eine JSON-Datei die Informationen darüber enthält, wie die App aussehen und wie sie sich bei der Installation auf einem mobilen Gerät verhalten soll. Zu den wichtigsten Angaben im Manifest zählen unter anderem der App Name, die Icons, die URL, die beim Start der App aufgerufen werden soll und der Anzeigemodus. Dieser bestimmt welche Browser-Benutzeroberfläche beim Start der App angezeigt werden soll. Eine ausführlichere Erklärung zum Manifest und zu den entsprechenden Properties kann hier gefunden werden.[5],[7]

Beispiel manifest.json

Funktionale Anforderungen

” Progressive Web Apps (PWA) are built and enhanced with modern APIs to deliver enhanced capabilities, reliability, and installability while reaching anyone, anywhere, on any device with a single codebase.”

Google [4]

Wie Google beschreibt, sollten PWAs fähig, zuverlässig und installierbar sein, um eine bestmögliche Nutzererfahrung zu erzielen. Dazu hat Google zwei PWA-Checklisten erstellt:

  • Core PWA Checklist: enthält Kriterien, welche die PWA installierbar und nutzbar für alle macht.
  • Optimal PWA Checklist: enthält Kriterien, um eine PWA zu entwicklen, die eine bestmögliche Nutzererfahrung bietet und gleichzeitig die Vorteile nutzt, die das Web leistungsstark machen.

Zusätzlich hat das Mozilla Developer Network (MDN) Prinzipien definiert, die eine PWA implementieren sollte, um als solche identifiziert zu werden:

  • auffindbar: Die App kann mithilfe von Suchmaschinen gefunden werden.
  • installierbar: Die App kann vom Homescreen aus gestartet werden.
  • verlinkbar: Die App kann durch das Versenden einer URL geteilt werden.
  • netzwerkunabhängig: Die App funktioniert auch bei schlechter/ keiner Netzwerkverbindung.
  • progressiv: Anwendung von Progressive Enhancement bei der Entwicklung der App.
  • responsive: Die App ist auf jedem Gerät nutzbar.
  • sicher: Verbindungen sind vor dem Zugriff von Dritten geschützt.[1]

Architektur einer PWA

Der beliebteste Ansatz eine PWA zu bauen, ist das App-Shell-Konzept. Dieses Konzept stellt einen Mix aus serverseitigem Rendern und clientseitigem Rendern dar und verwendet zusätzlich den offline-first Ansatz. Dabei werden für die Darstellung einer minimalen UI, die minimalen HTML-, CSS- und JavaScript-Dateien so früh wie möglich geladen. Gleichzeitig werden diese direkt gecached, sodass sie auch offline verfügbar sind. Hierbei handelt es sich sozusagen um das Skelett der Benutzeroberfläche. Beim nächsten Aufruf der Seite wird die UI aus dem Cache geladen und es müssen nur die Inhalte vom Server angefordert werden, welche sich noch nicht im Cache befinden. Mithilfe des Service Workers kann hier gesteuert werden, welche Inhalte gecached werden sollen. Die Verwendung einer App-Shell und das dynamische Laden des Inhalts bietet vor allem einen Performance Vorteil. Zusätzlich fühlt sich die Anwendung für den Nutzer sehr schnell und zuverlässig an, da der Nutzer sofort etwas sieht. Im Kontrast hierzu stehen weiße Seiten oder Ladeanzeigen, wie bei einer nativen Anwendung.[8], [9]

Beispiel einer App-Shell und des dynamischen Inhalts [8]

Unterstützung der Browser

Neben den technischen und funktionalen Anforderungen einer PWA ist es auch wichtig einen Blick auf die Browserkompatibilität zu werfen. Diese beinhaltet Funktionen und APIs die letztendlich die PWAs zu nativen Apps vergleichbar machen.

Projekt Fugu

Heutzutage ist es zwar möglich durch Web APIs auf native Funktionen zuzugreifen allerdings nicht auf alle. Diese Lücke zwischen den Möglichkeiten die das Web bietet und die der nativen Anwendungen nennt Google App Gap. Das Projekt Fugu versucht diese Lücke zu schließen.
Es ist ein Web Capabilites Projekt von Google, Microsoft und Intel bei dem der Browserunterbau Chromium weiterentwickelt wird. Auf diesem basieren unter anderem die Browser Google Chrome, Samsung Internet, Opera und die neue Version von Microsoft Egde. Im Projekt Fugu wird kontinuierlich evaluiert, welche nativen Funktionen gebraucht werden um dafür Web APIs zu entwickeln. Die Web APIs sind dabei so aufgebaut, dass die Plattformunterschiede abstrahiert werden. Das heißt der Webbrowser fungiert als zusätzliche Schicht zwischen Anwendung und Endgerät und ruft die passende native Schnittstelle auf.
Der Name des Projekts Fugu kommt übrigens daher, dass dieser Fisch in Japan unter richtiger Zubereitung eine Delikatesse ist. Ist dies nicht der Fall, ist der Fisch giftig. Im übertragenden Sinne ist hier also gemeint, dass die Entwicklung der APIs zu hervorragenden Anwendungen führen kann. Das ist allerdings nur möglich, wenn bei der Entwicklung immer die Kernwerte des Webs; die Sicherheit, das Vertrauen und die Privatsphäre gewahrt bleiben.[10], [11]
Auf der Fugu-Tracker Seite kann man sich anschauen, welche APIs schon umgesetzt worden sind oder in welchem Entwicklungsstadium sie sich befinden.

Schematische Funktionsweise der Fugu APIs [10]

Firefox

Die Entwickler des Firefox Browsers haben Ende 2020 bekannt gegeben, dass die Funktion von Site Specific Browsern (SSB) nicht länger unterstützt werden soll. Diese Funktion ermöglicht es Webseiten in minimaler UI darzustellen, also ohne Browser-Steuerungselemente. Dies ist die Voraussetzung, um eine PWA im Standalone Modus zu nutzen. Bislang war diese Funktion nur versteckt nutzbar und hatte darüber hinaus viele Fehler. Außerdem wurde herausgefunden, dass sie kaum Vorteile bietet. So ist die weitere Unterstützung von PWAs im Firefox Browser offen. Auch für die Zukunft gibt es laut den Firefox Entwicklern keine genauen Pläne ob und inwiefern PWAs weiter unterstützt werden sollen.[12]

Safari

Durch die Einführung der vollständigen Blockierung von Cookies von Drittanbietern erschwert Apple die Nutzung von PWAs im Safari Browser. Je nach Anwendungsfall braucht eine PWA Zugriff auf die Geräte APIs oder technische Strukturen wie den LocalStorage. Durch die Cookie Blockade werden alle lokalen Speicherdaten einer Seite gelöscht, wenn diese Seite sieben Tage lang nicht verwendet worden ist. Dadurch ist der offline-first Ansatz nicht mehr möglich. Schon simple Apps wie eine ToDo-Listen App sind nicht mehr richtig nutzbar, da die gespeicherten Daten nach sieben Tagen gelöscht werden. Die einzige Möglichkeit die 7-Tage-Lösch-Regel zu umgehen, ist die Anwendung zum Homescreen hinzufügen. Allerdings ist das keine Voraussetzung von PWAs. Hier bleibt offen, ob es Apple wirklich um den Datenschutz der Nutzer geht oder ob es nicht auch wirtschaftliche Gründe hat. Apple profitiert durchaus von den Einnahmen aus dem App Store, der mit PWAs umgangen wird.[13] Außerdem werden auch viele andere Funktionen, wie beispielsweise das Senden von Push-Benachrichtigungen oder das Anzeigen des Add2Homescreen-Buttons noch nicht unterstützt.[14]

Vor- und Nachteile einer PWA im Vergleich zu nativen Apps

Nun stellt sich natürlich die Frage, welche Vorteile PWAs eigentlich im Vergleich zu nativen Apps bieten und an welchen Stellen native Apps den PWAs überlegen sind?
Der wohl überzeugendste Vorteil einer PWA ist, dass mit nur einer Codebasis eine Anwendung implementiert werden kann, die nicht an eine bestimmte Plattform gebunden ist. Das bedeutet daher weniger Entwicklungsaufwand und damit verbunden weniger Entwicklungskosten. Ein weiterer Vorteil ist, dass kein Installieren der Anwendung notwendig ist. Darüber hinaus ist auch das Updaten deutlich einfacher, da der Nutzer nicht jede neue Version aus einem App Store laden muss, sondern ein einfacher Reload der Webseite ausreicht. Außerdem ist durch das Auffinden der Anwendung mithilfe einer Suchmaschine und dem Teilen durch das Versenden einer URL eine einfachere Zugänglichkeit möglich.
Einen Nachteil gegenüber nativen Apps haben PWAs vor allem bei der Benutzerfreundlichkeit. Die UX einer nativen Anwendung und das Gefühl, dass die Anwendung Teil des Geräts ist, ist nicht so einfach umzusetzen. Zusätzlich stellt die Hardwarezugänglichkeit eine weitere Herausforderung für PWAs dar. Diesem Nachteil wird jedoch durch die Verwendung und stetiger Entwicklung von modernen APIs versucht entgegenzuwirken. Mithilfe dieser sollen die Fähigkeiten von nativen Anwendungen auch für PWAs verfügbar werden. Ein weiterer Nachteil aus wirtschaftlicher Sicht ist die Monetarisierung, die bei PWAs nicht so einfach umzusetzen ist, wie bei nativen Apps, die kostenpflichtig im App Store erworben werden können.[4], [15]

Vorteile PWANachteile PWA
Single Codebasis ➜ schnellere &
günstigere Entwicklung
bestmögliche UX schwieriger
kein Installieren notwendigHardwarezugänglichkeit schwieriger
einfaches UpdatenMonetarisierung schwieriger
Auffindbarkeit

Performance Test

Zusätzlich zu den allgemeinen Vor- und Nachteilen einer PWA, soll nun die Performance von PWAs im Vergleich zu nativen Apps anhand eines Performance Tests genauer untersucht werden. Dazu wurde eine simple App konzipiert, die performance-kritische Inhalte enthält. Wie in der unterstehenden Abbildung zu sehen, besteht die App aus zwei Ansichten. Die erste Ansicht Lorem Picsum enthält viel Text und die zweite Ansicht Gallery beinhaltet viele Bilder.

Implementierte PWA für den Performance Test

Für den Performance Test wurden die folgenden drei Anwendungen implementiert:

  • Eine PWA mit Angular (11.0.5)
  • Eine iOS App (14.2) mit SwiftUI
  • Eine Android App (11.0) mit Java

Um die Performance zu bewerten, wurden zwei Szenarien festgelegt. Im ersten Szenario wurde gemessen, wie schnell die erste Ansicht (Loren Picsum) geladen wird. Im zweiten Szenario wurde die Zeit ermittelt, die der Ansichtswechsel von Ansicht eins (Loren Picsum) zu Ansicht zwei (Gallery) braucht. Für jede Anwendung wurden die Szenarien fünf mal getestet und anschließend der Mittelwert aus den gemessenen Zeiten berechnet. Die implementierten Apps wurden auf einem MacBook Pro 2016 (PWA) und auf einem iPhone 8 Plus (iOS) getestet. Da zum Testzeitpunkt kein Android Endgerät zur Verfügung stand, wurde hierfür auf das Tool BrowserStack zurückgegriffen.
Die Auswertung (siehe Darstellung unten) zeigt, dass im ersten Szenario die PWA und die iOS App mit einem Mittelwert von jeweils unter einer Sekunde sehr gut abgeschnitten haben. Die Android Implementierung hingegen mit 1,2 Sekunden ist im Vergleich deutlich langsamer. Dieses Ergebnis könnte allerdings auch darauf zurückzuführen sein, dass für den Performance Test der Android App das Tool BrowserStack verwendet wurde.
Im zweiten Szenario hat ebenfalls die PWA am schnellsten reagiert. Die iOS App hat im Vergleich fast doppelt so lang und die Android App fast dreimal so lang gebraucht.

Auswertung des Performance Tests

Zusammenfassend kann also gesagt werden, dass bei diesem Performance Test die PWA mit Abstand am besten abgeschnitten hat. Allerdings muss beachtet werden, dass es sich bei den durchgeführten Performance Tests um keine voll umfänglichen Tests handelt, sondern diese nur dazu dienen einen ersten Eindruck zu vermitteln. Außerdem kann nicht davon ausgegangen werden, dass eine PWA bezüglich Performance immer besser abschneidet als eine native App, da es hier auch immer darauf ankommt mit welchem Framework die PWA umgesetzt wird.

Lighthouse Audits

Performance Optimierung

Um die Performance der PWA noch genauer zu analysieren, wurde die Anwendung zusätzlich mit dem Tool Lighthouse ausgewertet. Dabei handelt es sich um ein Tool für die Optimierung von Webanwendungen. Welches unter anderem Tests für Performance, Barrierefreiheit, progressive Web Apps und SEO bietet. Lighthouse bewertet die Performance mithilfe der folgenden sechs Metriken:

  • First Contentful Paint: Dauer, bis der erste Text oder das erste Bild angezeigt wird
  • Speed Index: Dauer, wie schnell der Inhalt einer Seite sichtbar befüllt wird
  • Largest Contentful Paint: Zeitpunkt, an dem der größte Text oder das größteBild angezeigt wird
  • Time to Interactive: Zeit, die eine Seite benötigt um vollständig interaktiv zu sein
  • Total Blocking Time: Summe aller Zeitspannen, in der die Seite nicht auf Benutzereingaben reagieren kann, da der Mainthread blockiert ist
  • Cumulative Layout Shift: Summe aller unerwarteten Layout-Verschiebungen (ein sichtbares Element ändert seine Position von einem Frame zum nächsten)

Anhand dieser Metriken wird ein Performance Score zwischen 0 und 100 ermittelt. Nähere Informationen zu den Metriken und dem Score können hier gefunden werden.
Die erste Ansicht hat einen Performance Score von 86 erreicht und die zweite Ansicht einen Score von 58 (siehe Abbildung). Bei beiden Audits ist die Metrik Largest Contentful Paint im roten Bereich. Bei der zweiten Ansicht sind zusätzlich die Metriken Total Blocking Time und Cumulative Layout Shift rot. Letzteres liegt vor allem daran, dass diese Ansicht viele Bilder enthält. Diese werden nacheinander geladen und sorgen so für Verschiebungen des Layouts. Das wirkt sich vor allem negativ auf die UX aus.[16], [17]

Lighthouse Audits vorher


Zusätzlich enthält der Lighthouse Bericht Empfehlungen, wie die Seite schneller laden könnte und Diagnosen mit weiteren Informationen über die Performance der Anwendung. Mithilfe dieser Informationen konnte auch durch die Anwendung einer Text Kompression mittels gzip und der Verwendung von online CSS statt separaten CSS-Dateien, die implementierte PWA verbessert werden. Außerdem bekamen alle img-Elemente, der verwendeten Bilder der PWA, eine feste Größe und wurden in einer geringeren Auflösung als zuvor bereitgestellt. Dadurch konnte der Performance Score der Ansichten deutlich optimiert werden, sodass die erste Ansicht nun einen Score von 97 und die zweite Ansicht einen Score von 98 erreichen konnte. Darüber hinaus sind alle Metriken im grünen Bereich. (siehe Abbildung)

Lighthouse Audits nachher

PWA Audits

Neben der Performance Auswertung sind in diesem Kontext auch die PWA Audits interessant, bei dem mit Lighthouse verschiedene Aspekte einer PWA validiert werden können. Die Validierung wird in drei Testbereiche unterteilt:

  • fast and reliable: Hier wird überprüft, ob die Seite schnell und zuverlässig lädt, unabhängig von der Netzwerkverbindung.
  • installable: Hier wird überprüft, ob die Bedingungen erfüllt sind, dass die PWA installierbar ist. Dazu zählt unter anderem, dass ein Service Worker registriert ist und dass das Manifest alle notwendigen Voraussetzungen erfüllt.
  • PWA Optimierung: Hierzu zählen Aspekte, die eine PWA optimieren, wie beispielsweise, dass der Inhalt responsive ist oder dass die Anwendung HTTPS anstatt HTTP verwendet.

Die implementierte PWA hat auch bei diesem Test gut abgeschnitten. Sie erfüllt in den Testbereichen fast and reliable sowie installable alle Aspekte. Lediglich im Bereich PWA Optimierung wurde ein Aspekt nicht erfüllt, da aufgrund der Entwicklung mit einem lokalen Server die Verwendung von HTTPS nicht möglich war.[18]

Fazit

Zusammenfassend lässt sich sagen, dass PWAs vor allem den Vorteil bieten, dass sie crossplattform entwickelt werden können. Dadurch entstehen weniger Kosten und die Apps können auf jedem Gerät ohne Installation verwendet werden. Allerdings können mit Web APIs noch nicht alle nativen Funktionen implementiert werden. Deshalb, um auf die Eingangsfrage zurückzukommen, können PWAs im Moment native APPs nicht komplett ersetzen. Google ist zwar ein großer Vorreiter und auch mit dem Projekt Fugu wird versucht die App Gap zu schließen, aber insgesamt gibt es noch zu wenig Unterstützung, vor allem von Firefox und Safari. Gerade iPhone Nutzer sind, zumindest im Moment, an Safari gebunden und können so nur wenig Funktionalitäten von PWAs nutzen.
Allerdings ist es abhängig vom Anwendungsfall möglich, dass PWAs native Apps ersetzen, wie etwa bei der Bestellung/Bezahlung in einem Restaurant. Für diesen Anwendungsfall wurde beispielsweise von Starbucks eine PWA implementiert, die es den Kunden ermöglicht schnell und einfach eine Bestellung aufzugeben.
Es bleibt auf jeden Fall spannend, was in Zukunft passiert und wie sich PWAs und deren Unterstützung weiterentwickeln.

Hands On

Hier sind noch ein paar weiterführende Links rund um das Thema Progressive Web Apps:

  • PWA Stats: Liste mit Statistiken und Neuigkeiten rund um Progressive Web Apps
  • PWA Bar: Auswahl der besten Progressive Web Apps
  • What Web can do today: Übersicht der verfügbaren Funktionen und welche Browser diese unterstützen
  • PWA Builder: Open-Source Projekt von Microsoft um PWAs zu erstellen
  • Web.dev: Sammlung von Artikeln der Google Developer zu PWAs

Quellen

[1]  MDN contributors, Introduction to progressive web apps
[2]  MDN contributors, Progressive Enhancement
[3]  A. Russell, Progressive Web Apps: Escaping Tabs Without Losing Our Soul
[4]  P. LePage, Sam Richard, What are Progressive Web Apps?
[5]  MDN contributors, Progressive web apps (PWAs)
[6]  M. Gaunt, Service Workers: an Introduction
[7]  F. Beaufort, Pete LePage, Add a web app manifest
[8]  A. Osmani, The App Shell Model
[9]  MDN contributors, Progressive web app structure
[10] C. Liebel, Project Fugu – neue Fähigkeiten braucht das Web
[11]  K. Münster, What Is Project Fugu — Google’s Initiative To Unlock All Native Device Features For The We
[12]  S. Grüner, Firefox soll PWA nicht unterstützen
[13]  D. Petereit, Unter dem Deckmantel des Guten: Apples neuer Safari-Browser behindert die Entwicklung von progressiven Web-Apps
[14]  A. Bar, What web can do today?
[15]  A. Verhoeven, Native app vs. progressive web app (PWA): Everything you need to know
[16]  Google, Lighthouse
[17]  Google Developers, Lighthouse performance scoring
[18]  Google Developers, PWA audits

ServiceWorker – Offline First

In der Vorlesung Rich Media haben wir uns viel mit Performance in Web Anwendungen beschäftigt. Dabei habe ich mich mit ServiceWorkern in Bezug auf Offlinenutzung, Funktionalität und Performance beschäftigt. Zuerst habe ich mich damit befasst, wie ein ServiceWorker funktioniert. Danach habe ich geschaut, wie sich die Nutzung eines ServiceWorker und des Ansatzes Offline First auf die Performance auswirkt.

Continue reading

WebSocket-Protokoll: Ein detaillierter technischer Einblick

Das HTTP-Protokoll existiert seit Beginn des Internets und hat sich bis heute in Bezug auf Performance immer weiter entwickelt. Die vielen TCP-Verbindungs-Aufbau-Prozeduren wurden durch das Multiplexing auf ein paar Wenige reduziert, welche jeweils mehrere verschiedene Daten übertragen [7]. Auch der Header selbst wurde auf Performance getrimmt. So wurde aus dem textuellen Format ein binär-Kodiertes. Zudem wurden neue Funktionen wie das Caching hinzugefügt, um das Laden von Daten zu minimieren [7][8].

Jedoch funktioniert das HTTP-Protokoll in seiner Grund-Funktionalität immer noch gleich. Es besteht immer noch aus einer Anfrage und einer Antwort und die Verbindung kann nicht beliebig lange offen gehalten werden.

Es ist dem Server nicht möglich, von sich aus Daten an den Client zu senden. Dieser Datenaustausch kann nur vom Client initiiert werden [7][8].

Hier knüpft das WebSocket-Protokoll [2] an. Es bietet eine bidirektionale Datenübertragung, welche es dem Server erlaubt, direkt ohne Client-Anfrage Daten zu senden, was das Realisieren von Echtzeit-Web-Anwendungen ohne große Netzlast oder Latenz ermöglicht. Zudem ist der Header sehr klein und einfach zu interpretieren. Dadurch ist das Protokoll sehr gut zum Senden vieler kleiner Nachrichten geeignet.

Im Folgenden werden zunächst allgemeine Informationen und wichtige Eigenschaften des WebSocket-Protokolls beschrieben und die Vorteile und Nachteile gegenüber dem HTTP-Protokoll offen gelegt. Daraufhin wird ein detaillierter technischer Einblick in die Implementierung und Funktionsweise des Protokolls gegeben. Am Schluss wird die JavaScript-WebSocket-API als Beispiel-API für die Client-seitige WebSocket-Implementierung vorgestellt und deren Funktionen mit dem internen Verhalten des Protokolls in Beziehung gesetzt.

Allgemein

Das WebSocket-Protokoll ist ein seit 2011 existierendes Internet-Protokoll, welches auf der Anwendungsschicht des OSI-Modells angesiedelt ist und der bidirektionalen Daten-Übermittlung über einer konstanten TCP-Verbindung dient. Dabei werden die Standard-HTTP-Ports mit verwendet, also 80 oder 8080 bei unverschlüsselten und 443 bei verschlüsselten Verbindungen. Dies hat den Vorteil, dass keine zusätzlichen Firewall-Einstellungen nötig sind, um das WebSocket-Protokoll zu berücksichtigen [9]. Das WebSocket-Protokoll ist im RFC 6455 von der IETF (Internet Engineering Task Force) standardisiert und aktuell in der Version 13 verfügbar [2]. Es dient primär der Echtzeit-Datenübertragung bei Echtzeit-Web-Anwendungen.

Protokoll-Eigenschaften

Im Folgenden werden wichtige Eigenschaften des WebSocket-Protokolls genannt und die daraus entstehenden Einschränkungen und Vorteile gegenüber dem HTTP-Protokoll beschrieben.

Übertragung großer Daten

Wie beim HTTP-Protokoll auch, können größere Daten, welche nicht auf einmal in einen Puffer passen, wie zum Beispiel größere Dateien, Stück für Stück versendet werden. Hierbei ist aber keine Fragmentierung auf Anwender-Schicht notwendig. Die Nachricht wird als eine große Nachricht mit einem Header und großer Payload interpretiert, welche je nach Puffer-Größe Stück für Stück eingelesen wird. Anhand der im Header gegebenen Payload-Größe und der bisher empfangenen Payload-Daten kann ermittelt werden, ob noch Daten fehlen oder die Nachricht vollständig ist [10].

In Abbildung 1 ist die entsprechende Nachricht und der verfügbare Puffer veranschaulicht.

Senden großer Daten durch Stück-weises einlesen in den Puffer
Abbildung 1: Senden großer Daten durch Stück-weises einlesen in den Puffer

Da dieses Verfahren von beiden Protokollen unterstützt wird, existieren hier weder Vor- noch Nachteile.

Verbindungsorientiert + konstante Verbindung + kleiner Header

Das WebSocket-Protokoll ist verbindungsorientiert [2]. Dies bedeutet, dass zunächst eine HTTP-Anfrage und eine entsprechende Antwort geschickt werden muss, bevor die eigentlichen Daten versendet werden können [7]. Dies erzeugt zunächst einen Mehraufwand in Form von Verarbeitungs-Aufwand und der Größe an Daten, welche gesendet werden müssen. Sollten jedoch mehrere Daten über eine konstante Verbindung ohne erneuten Verbindungsaufbau gesendet werden, kann das WebSocket-Protokoll seine Stärke ausspielen. Der Header des WebSocket-Protokolls ist deutlich kleiner als der des HTTP-Protokolls, auch wenn der HTTP-Header binär kodiert sein sollte. Zudem muss das HTTP-Protokoll pro Daten-Transfer zwei Header, eine Anfrage und eine Antwort, senden. Somit ist der Aufwand pro Nachricht beim WebSocket-Protokoll geringer, was bei vielen zu übermittelnden Nachrichten einen großen Vorteil bringt. Da bereits das HTTP/1.1-Protokoll mit Multiplexing-Funktionalitär ausgestattet ist [7], kann der entscheidene Vorteil darin gesehen werden, dass das WebSocket-Protokoll eine konstante Verbindung besitzt, sodass die zu übertragenden Daten nicht zu Beginn der Übertragung bekannt sein müssen, was bei HTTP-Multiplexing aber der Fall ist, da die HTTP-Verbindung wieder geschlossen werden muss.

Die folgende Formel gibt an, ab welcher Nachrichten-Anzahl sich der Einsatz von WebSockets lohnt, wenn für HTTP Multiplexing verwendet werden kann. Mit ‘WS-Header‘ oder ‘HTTP-Header‘ ist der Aufwand gemeint, welcher mit dem Versenden und Erstellen beziehungsweise Lesen des entsprechenden Headers einhergeht. Der linke Teil gibt den Aufwand des WebSocket-Protokolls, der rechte Teil den Aufwand für das HTTP-Protokoll an. ‘n‘ entspricht der Anzahl an Nachrichten [10].

2 HTTP-Header + n WS-Header + 2 WS-Header < n*2 HTTP-Header

Die zusätzlichen 2 WS-Header entsprechen dem Verbindungs-Abbau.

Maskierung

Da beim Hochladen von Daten die Payload maskiert werden muss [2], entsteht beim WebSocket-Protokoll ein Mehraufwand. Je größer die Payload einer Nachricht ist, desto mehr muss maskiert werden, was die Gesamt-Übertragungszeit reduziert. Daher sollten beim Hochladen von Daten, der Payload-Anteil möglichst gering gehalten werden.

Bidirektional vs. Polling

Bidirektional bedeutet, dass zu einer beliebigen Zeit einer der Teilnehmer eine Nachricht an die Gegenstelle senden kann. Dadurch ist es dem Server möglich, Nachrichten an den Client zu senden, ohne eine vorherige Anfrage erhalten zu haben. Dies ist vor allem in Anwendungsgebieten von Vorteil, in denen der Server dem Client möglichst schnell Zustands-Aktualisierungen mitteilen muss. Anwendungs-Gebiete sind hierbei Echtzeit-Anwendungen wie Browser-Spiele [5], in welchen der Spieler möglichst schnell vom Server informiert werden muss, wenn zum Beispiel ein neuer Gegner in sein Sichtfeld gerät. Mit Hilfe des WebSocket-Protokolls kann der Server daher direkt eine Nachricht senden, was der Latenz einer Daten-Übertragung für eine Strecke entspricht.

Die selbe Funktionalität mit dem HTTP-Protokoll muss mit Hilfe von Polling implementiert werden [6]. Dabei wird regelmäßig eine Anfrage gesendet, um den aktuellen Server-Zustand abzufragen. Dabei verursacht das permanente Abfragen eine große Netzlast, was beim WebSocket-Protokoll nicht der Fall ist. Darüber hinaus ist die Latenz meist deutlich höher und abhängig von der Abfrage-Frequenz des Clients.

In Abbildung 2 und 3 wird die Eigenschaft der Bidirektionalität und das Polling-Verfahren visuell veranschaulicht.

Server-Mitteilung mit bidirektionaler Datenübertragung.
Abbildung 2: Server-Mitteilung mit bidirektionaler Datenübertragung
Abbildung 3: Server-Mitteilung mit Polling-Verfahren

Keine Same-Origin-Policy

Das WebSocket-Protokoll folgt im Gegensatz zum HTTP-Protokoll keiner Same-Origin-Policy [1]. Es können also mehrere Verbindungen mit unterschiedlichen Domänen existieren. Um Sicherheitsprobleme wie Cross-Site-Scripting zu umgehen, muss der Server beim Verbindungsaufbau den mitgelieferten Origin-Header mit der eigenen Domäne abgleichen und eventuell die Verbindung trennen, wenn die Domäne der Client-Anwendung keine Valide ist.

Anwendungsgebiete

Anwendungsgebiete für das WebSocket-Protokoll sind alle Anwendungen, welche möglichst alle Eigenschaften und deren Einschränkungen des Protokolls optimal nutzen können. Primär wird das WebSocket-Protokoll in Echtzeit-Anwendungen wie Browser-Spielen [5], Chat-Anwendungen oder beim Streaming verwendet. Browser-Spiele tauschen viele kleine Nachrichten zwischen Server und Client aus. Zudem muss der Server dem Client schnellstmöglich mitteilen, wenn sich der Spiel-Zustand insofern ändert, dass es den entsprechenden Spieler betrifft. Aber auch beim Monitoring kann das WebSocket-Protokoll bestmöglich eingesetzt werden, da auch hier ein schneller bidirektionaler Datenverkehr zwischen Server und Client benötigt wird. Zudem kann durch das Verbinden mit verschiedener Domänen, der Zustand mehrerer Server eines größeren Netzwerks visualisiert werden [10].

Verbindungsaufbau

Der Verbindungsaufbau des WebSocket-Protokolls entspricht einem klassischen HTTP-Zyklus bestehend aus Anfrage und Antwort. Im Folgenden sind die Minimal-Header für Anfrage und Antwort gegeben [1].

HTTP-AnfrageHTTP-Antwort
GET /<URL> HTTP/1.1
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: <String-In>
Sec-WebSocket-Version: <Version-in>
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: <String-Out>
Sec-WebSocket-Version: <Version-out>
Tabelle 1: Minimaler Anfrage/- und Antwort-HTTP-Header für WebSocket-Verbindungsaufbau [1]

Die zu übergebende <URL> kann beliebig gewählt werden, da diese für das WebSocket-Protokoll keine Bedeutung hat. Typischerweise wird die <URL> daher zur Differenzierung verschiedener WebSocket-Anwendungen, welche parallel auf dem Server laufen, verwendet [1].

Um dem Server mitzuteilen, dass auf das WebSocket-Protokoll gewechselt werden soll, müssen die Header ‘Upgrade‘ und ‘Connection‘ verwendet werden.

Im ‘Sec-WebSocket-Version‘-Header wird die vom Client unterstützte WebSocket-Version <Version-in> angegeben. Meistens entspricht dies der aktuellen Version 13 [10].

Vor dem Senden einer WebSocket-Nachricht muss der Client sicher stellen, dass der kontaktierte Server das WebSocket-Protokoll auch versteht. Andernfalls bestünde die Gefahr, dass der Server fälschlicherweise eine WebSocket-Nachricht als HTTP-Nachricht interpretiert, was zu einer Sicherheitslücke führt. Aus diesem Grund muss ein Base64-kodierter String <String-in>, welcher beliebig gewählt werden kann, im ‘Sec-WebSocket-Key‘-Header mitgeliefert werden. Der Server muss diesen entsprechend der in Tabelle 2 angegebenen Schritte konvertieren und das Ergebnis in seiner Antwort im ‘Sec-WebSocket-Accept‘-Header zurück senden [1].

Zusätzlich kann der Server eine WebSocket-Version <Version-out> angeben, falls diese von der Angabe des Clients <Version-in> abweicht.

Konnte keine Vereinbarung bezüglich der Version oder des Wechsels auf das WebSocket-Protokoll getroffen werden oder der zurück gelieferte String <String-out> falsch sein, wird der Verbindungsaufbau abgebrochen [1].

BeschreibungBeispielLänge (Byte)
<String-In>: beliebiger Base64-StringMQBbM45rKkPH/ocIaDfOjw==24
Konkatinierung mit statischem StringMQBbM45rKkPH/ocIaDfOjw==258EAFA5-E914-47DA-95CA-C5AB0DC85B1160
sha1-Hash2e9a036975af28d8828712ff45a733eb4d9c2f5340
Hex -> Int<nicht darstellbar>20
base64: <String-Out>LpoDaXWvKNiChxL/Racz602cL1M=28
Tabelle 2: Sec-WebSocket-Key-Konvertierung [1] [10]

WebSocket-Header

Der WebSocket-Header ist binär kodiert und in seiner Größe variabel. Er kann je nach Payload-Größe und Übertragungs-Richtung bis zu 14 Byte umfassen und eine minimale Größe von 2 Byte betragen [1][2], was im Gegensatz zum HTTP-Header, auch wenn dieser binär kodiert sein sollte, deutlich kleiner ist. In Abbildung 4 ist der WebSocket-Header mit seinen Bestandteilen dargestellt. Im Folgenden werden diese detailliert beschrieben.

Abbildung 4: WebSocket-Header [1]

Opcode

Der Opcode, auch Operation-Code genannt, gibt den Typ der Nachricht an [2]. Aktuell sind folgende sechs Nachrichten-Typen definiert:

CodeBeschreibung
0x0Continuation (Kontroll-Rahmen)
0x1Text (Payload-Typ: UTF-8-Text)
0x2Binary (Payload-Typ: Binär-Format)
0x3-0x7not used
0x8Close (Kontroll-Rahmen)
0x9Ping (Kontroll-Rahmen)
0xaPong (Kontroll-Rahmen)
0xb-0xfnot used
Tabelle 3: verfügbare Opcodes des WebSocket-Header

Die Opcodes ‘Text‘ und ‘Binary‘ geben an, dass in der Payload Anwendungs-bezogene Daten enthalten sind. Bei ‘Text‘ muss die Payload als UTF-8-String, bei ‘Binary‘ als Binär-Daten interpretiert werden. Die restlichen vier Kontroll-Rahmen werden in nachfolgenden Kapiteln mit Ihrem jeweiligen Verwendungszweck beschrieben.

Fin – Fragmentierung auf Anwendungsschicht

Das Fin-Flag wird im Zusammenhang mit dem Opcode ‘Continuation‘ verwendet, um Fragmentierung auf Applikations-Schicht zu ermöglichen. Dabei wird das Fin-Bit nur gesetzt, wenn es sich bei der Nachricht um das letzte Fragment der Gesamt-Nachricht handelt. Der Opcode wird zu Beginn auf den Daten-Typ der Payload, also ‘Text‘ oder ‘Binary‘ gesetzt. Der Daten-Typ ist dabei für alle Fragmente einer Gesamt-Nachricht der Selbe. Alle nachfolgenden Fragmente müssen mit Opcode ‘Continuation‘ gekennzeichnet werden [1][2].

In Tabelle 4 ist das Zusammenspiel zwischen Opcode und Fin-Flag bei fragmentierter und nicht-fragmentierter Nachricht veranschaulicht. Aus [1] inspiriert.

FinOpcodeBeschreibung
11,2Nachricht nicht fragmentiert.
01,2Nachricht mit Typ 1,2 beginnt.
=> weitere Nachrichten folgen, um Payload zu vervollständigen.
00Weiterer Teil der Nachricht mit Typ 1,2.
10Letzter Teil der Nachricht.
=> Payload jetzt vollständig.
Tabelle 4: Zusammenspiel zwischen Opcode und Fin-Flag bei fragmentierter und nicht-fragmentierter Nachricht.

Mask

Wenn das Mask-Flag gesetzt ist, ist die Nachricht gemasked. Dies bedeutet, dass die Payload der Nachricht mit dem mitgelieferten 4-Byte großen Mask-Key XOR-Verschlüsselt wurde. Das Ver/- und Entschlüsselungs-Verfahren ist dabei das Selbe und im Folgenden mit Programm-Code beschrieben, welcher von [1] inspiriert wurde:

for (unsigned int i = 0; i < payloadSize; ++i) {
     pBuffer[i] = pPayload[i] ^ pMaskKey[i % 4];
}

‘pBuffer’ enthält hierbei nach dem Verfahren entweder die verschlüsselte oder entschlüsselte Version der Payload, jenachdem, ob die Payload ‘pPayload’ ver/- oder entschlüsselt vorliegt.

Wichtig ist hierbei, dass nur Nachrichten vom Client zum Server gemasked werden müssen. Nachrichten vom Server zum Client dürfen nicht gemasked werden [2].

Sollte eine unverschlüsselte Nachricht dem Server oder eine Verschlüsselte dem Client gesendet werden, muss der Empfänger die Verbindung schließen [1].

Payload-Größe

Die Anzahl der benötigten Bytes für die Kodierung der Payload-Größe ist je nach Payload-Größe unterschiedlich. Um die Größe der Payload zu ermitteln müssen zunächst die 7 Bit des ‘Payload-Len’-Feldes interpretiert werden. Sollte dieser Wert kleiner als 126 sein, so entspricht dies der Payload-Größe. Sollte der Wert aber 126 oder 127 sein, so müssen weitere Bytes eingelesen werden und deren Wert als Payload-Größe interpretiert werden. Bei 126 sind es 2 Byte, bei 127 8 Byte, die zusätzlich eingelesen werden müssen [1]. Dadurch müssen bei kleineren Nachrichten unnötige Bytes nicht mitgesendet werden, da sich die Anzahl der zur Kodierung der Payload-Größe benötigten Bytes von der Nachrichten-Größe abhängt.

RSV

RSV steht für ‘Reserved‘ und stellt bisher ungenutzte Bits im Header dar, welche für eventuell spätere Protokoll-Erweiterungen in der Spezifikation reserviert sind.

Verbindungsabbau

Um eine WebSocket-Verbindung zu schließen, kann einer der Teilnehmer zu jeder Zeit eine Nachricht mit dem Opcode ‘Close‘ senden. Die Gegenstelle muss dann eine entsprechende Close-Nachricht zurück senden. Die Payload der Close-Nachricht ist in zwei Abschnitte eingeteilt, welche zusammen nicht größer als 125 Byte sein dürfen. Hierbei entsprechen die ersten 2 Byte dem Close-Code, einer ID zur exakten Bestimmung des Schließ-Grunds. Alle nachfolgenden Bytes enthalten, wenn vorhanden, eine textuelle Beschreibung des Close-Codes [1]. Meistens wird jedoch nur der Close-Code gesendet [10].

Nach dem Senden oder Empfangen einer Close-Nachricht dürfen keine weiteren Nachrichten gesendet und empfangene Nachrichten nicht mehr berücksichtigt werden [1].

Zusätzliche Funktionen

Pings und Pongs

Sollte die Gegenstelle auf Anwender-Schicht nicht mehr erreichbar sein, so können Ressourcen gespart werden, wenn die Verbindung getrennt wird. Um zu erkennen, ob ein anderer Teilnehmer noch erreichbar ist, oder nicht, können zu einem beliebigen Zeitpunkt, Nachrichten mit dem Opcode ‘Ping‘ gesendet werden. Die Payload kann hierbei beliebig gewählt werden, darf aber die Maximal-Größe von 125 nicht überschreiten. Durch den Empfang einer entsprechenden Ping-Nachricht ist der Empfänger dazu gezwungen, eine Nachricht mit dem Opcode ‘Pong‘ zurück zu senden. Dabei muss die Payload der Pong-Nachricht den Daten der Ping-Nachricht entsprechen [1].

Wann genau eine Ping-Nachricht gesendet werden sollte, ist in der Spezifikation nicht definiert und daher der Anwendung überlassen [2]. Die Anwendung könnte die vergangene Zeit seit der letzten angekommenen Nachricht von einem bestimmten Teilnehmer messen. Sollte diese einen bestimmten festgelegten Wert überschreiten, könnte eine Ping-Nachricht gesendet werden. Auf die entsprechende Pong-Antwort kann nun wiederum eine bestimmte festgelegte Zeit gewartet werden. Sollte bis dahin keine Pong-Nachricht ankommen, kann die TCP-Verbindung geschlossen werden [10].

Bisher konnte aber die Erfahrung gemacht werden, dass der ‘Firefox’-Browser [12] keine Ping-Nachrichten an den selbst erstellten Server gesendet hat. Dies liegt eventuell daran, dass der Browser erkennt, dass der Server lokal erreichbar ist, was bedeutet, dass sich beide Teilnehmer auf der selben Maschine befinden wodurch das Senden einer Ping-Nachricht damit unnötig ist [10].

Sollten mehrere Pings gesendet werden, genügt es, einen Pong als Antwort zu senden. Pong-Nachrichten ohne dazugehörige Ping-Nachricht werden ignoriert [1].

Sub-Protokolle

Subprotokolle dienen der Kennzeichnung bezüglich der Kodierung einer Payload. Beinhaltet die Payload beispielsweise einen JSON-String, so kann durch ein Sub-Protokoll dem Server mitgeteilt werden, dass er einen JSON-Parser zum interpretieren der Payload verwenden soll. Die Mitteilung der Sub-Protokolle geschieht über einen eigenen HTTP-Header während dem Verbindungs-Aufbau. Über den HTTP-Header ‘Sec-WebSocket-Protocol‘ können ein oder mehrere Sub-Protokolle beim Server angefragt werden, zum Beispiel mehrere Versionen eines Parsers. Der Server sendet dann das erste passende Sub-Protokoll über selbigen Header zurück an den Client [1].

JavaScript WebSocket-API

Im Folgenden werden die wichtigsten Funktionen der WebSocket-API für die Sprache JavaScript auf Client-Seite kurz erläutert, und im Parallelen veranschaulicht, welche Funktionen zu welchen Aktionen intern im Browser führen, bezogen auf das WebSocket-Protokoll. Die dafür nötigen Informationen wurden aus [3] und [4] entnommen.

Verbindungsaufbau

var ws = new WebSocket(<URL>, <subProtocols>);

Das Erzeugen eines WebSocket-Objekts entspricht dem WebSocket-Verbindungs-Aufbau. Der erste Parameter entspricht der <URL>, über welche der Server und eine auf dem Server laufende WebSocket-Anwendung gewählt werden kann, zu der eine Verbindung aufgebaut werden soll. Zu Beachten gilt, dass das ‘http://‘ oder ‘https://‘ in typischen HTTP-URL’s mit einem ‘ws://‘ für ‘WebSocket’ beziehungsweise einem ‘wss://’ für ‘WebSocket Secure‘ bei sicheren Verbindungen ersetzt werden muss.

Der zweite Parameter ist optional und kann zur Angabe bestimmter Sub-Protokolle verwendet werden. Hierbei kann entweder ein String oder Array von Strings übergeben werden.

ws.onopen = ()=>{};

Bei erfolgreichem Verbindungsaufbau wird der Anendungs-Code durch den onopen-Listener informiert.

Senden

ws.send(<Content>);

Das Senden von Daten geschieht über die send-Funktion des WebSocket-Objekts. Jenachdem, welche Objekte als Parameter übergeben werden, wird der Obcode im WebSocket-Header gesetzt. Tabelle 5 stellt alle möglichen Kombinationen zwischen übergebenem Objekt und Opcode dar.

<Content>Opcode
StringText
ArrayBuffer / BlobBinary
Tabelle 5: Mapping zwischen übergebenem Parameter und Opcode

Empfangen

ws.onmessage = ev=>{ev.data;};
ws.binaryType = <Type>;

Für den Empfang von Daten, wird der onmessage-Listener benötigt, welcher informiert wird, sobald die Payload der Nachricht vollständig vorliegt. Die für den Empfang zur Verfügung stehenden Objekte sind die Selben wie für das Senden. Jedoch muss beim Empfang einer Nachricht mit Opcode ‘Binary‘ zusätzlich bestimmt werden, ob ein ArrayBuffer-Objekt oder ein Blob-Objekt empfangen werden soll, da beide jeweils Binär-Formate darstellen. Dafür wird das Objekt-Feld ‘binaryType‘ verwendet. Ein Überblick über die möglichen Werte und deren Beziehungen ist in Tabelle 6 gegeben. ‘-‘ bedeutet, dass der Wert nicht berücksichtigt wird.

OpcodebinaryTypeev.data
TextString
Binary“arraybuffer”ArrayBuffer
Binary“blob”Blob
Tabelle 6: Abhängigkeiten zwischen Opcode, <Type> und ev.data

Verbindungsabbau

ws.onclose = ev=>{};
ws.close(<Code>, <Msg>);

Für den Verbindungsabbau existieren zum Empfangen einer Close-Nachricht ein entsprechender Listener und zum Senden einer Close-Nachricht eine Sende-Funktion. Hierbei muss aber beim Empfang einer Close-Nachricht keine Close-Nachricht manuell zurück gesendet werden. Dies wird vom Browser-Laufzeit-System übernommen. Sowohl das Event-Objekt, als auch die Sende-Funktion besitzen die Möglichkeit, den Close-Code, sowie eine optionale textuelle Close-Nachricht zu empfangen beziehungsweise zu senden.

Payload-BestandteilSendenEmpfangen
Close-Code<Code>ev.code
Close-Message<Msg>ev.reason
Tabelle 7: Komponenten zum Lesen und Schreiben der Close-Payload

Fehlermeldung

ws.onerror = ()=>{};

Sollte während der WebSocket-Kommunikation ein Fehler auftreten, kann dieser über den ‘onerror‘-Event-Listener mitgeteilt werden. Jedoch wird hier lediglich ein Event-Objekt übergeben, welches keinerlei Informationen über den Fehler enthält. Ein entsprechender Fehler-Code ist immer nur im Close-Code enthalten, da darüber alles kommuniziert wird, was das Schließen der Verbindung bewirkt hat, also auch Fehler [11].

Socket.io

‘Socket.io’ ist eine abstraktere JavaScript-Bibliothek für Client- aber auch Server-seitige Echtzeit-Kommunikation mit einer einheitlichen Schnittstelle, welche die Verwendung und Einbindung von Echtzeit-Kommunikation in Web-Anwendungen erleichtern soll. Dabei wird je nach Kompatibilität der darunterliegenden Technologien, im Hintergrund entweder auf HTTP mittels Polling oder auf das WebSocket-Protokoll zugegriffen. ‘Socket.io’ bietet aber noch weitere Funktionalitäten wie zum Beispiel Echtzeit-Analysen [13].

Quellen

Progressive Web Apps – Wer braucht noch eine native App?



Beispiele zum Einstieg

Progressive Web Apps sind schon weiter verbreitet wie man denkt. Auch große, innovative Unternehmen Twitter, Airbnb, Spotify oder Tinder setzen auf Progressive Web Apps.

Abb. 1: Eine Auswahl von Progressive Web Apps [1]


Wer sich ein tolles Beispiel anschauen möchte, dem empfehle ich https://riorun.theguardian.com/ (auf mobile) zu testen. Nach einiger Zeit erscheint ein Popup, das fragt, ob man die App zum Startbildschirm hinzufügen möchte. Bestätigt man diese Abfrage, wird die PWA im Hintergrund auf dem Gerät installiert und ist ab sofort wie jede andere App auf dem Gerät verfügbar.

Abb. 2: Rio Run App von the Guardian [2]

Weitere tolle PWAs finden sich auf den Übersichtsseiten von:
https://pwa.rocks/
https://progressivewebapproom.com/

Historische Entwicklung

Kurz nach der Einführung des ersten iPhones hatte Steve Jobs schon die nächste Vision für sein Schmuckstück. Für ihn war nicht das Gerät an sich, viel mehr der Browser, der Hafen zum Tor der neuen Welt. Seiner Vision nach, sollte ein Smartphone bestenfalls nur noch einen Browser beinhalten. Entwickler können Apps über das Web bereitstellen, die sich vollständig in Safari integrieren lassen und sich selbstständig im Hintergrund updaten. [3]. Die Idee ist gut, allerdings, typisch Jobs, ihrer Zeit voraus. Die Erfolgsgeschichte des iPhones zwang Apple an den Rand der Kapazitäten, so dass vermutet werden kann, dass Apple schlichtweg keine Zeit und Ressourcen hatte das Thema PWA weiter zu verfolgen. Mit der Masse an Apps, die in den Store drang, hatte man mehr als genug zu tun. Die ersten, die nach Steve Jobs das Thema wieder aufgegriffen haben, waren Mozilla, mit der Veröffentlichung des FirefoxOS im Jahr 2013. Ein Betriebssystem, das es ermöglicht Web Apps als native Apps auf dem Endgerät laufen zu lassen. [3] In den Jahren 2006-2013 hat sich auch sonst viel getan: Endgeräte haben unfassbar an Performance gewonnen, die Webentwicklung hat JQuery und PHP hinter sich gelassen. Neue Möglichkeiten, neue Frameworks und ausgefuchste CSS-Kniffe ermöglichen seitdem eine völlig neue Form der User Experience im Web. Und Web? An wen denken wir da im Web? Genau, Google! Und Google hat ein Problem: Auch wenn sie selbst einen App Store betreiben und sich Kniffe haben einfallen lassen, wie sich Apps indexieren lassen, ist eine native App nicht in der Form auswertbar für ihre Suchmaschine, wie der Content einer Website. So fordert Alex Russells, Chrome Engineer bei Google, im Jahr 2015, die Einführung von Progressive Web Apps (PWA), eine Kombination aus aktueller Web Technologie mit den modernsten Möglichkeiten des Browsers [3]. Mit geschicktem Marketing und einer großen User-base überzeugte Google nun auch Apple wieder an dem Thema zu arbeiten, die 2017 mit der Unterstützung vom PWAs in Safari gleichzogen, komplettiert von Microsoft, dem schlafenden Giganten, der 2018 vollen Support für PWAs im Edge Browser verkündete [4]. Somit ist das große Trio vollends am Start und einer Erfolgsgeschichte von PWAs steht nichts mehr im Wege!

Was bedeutet Progressive Web App?

Vom Naming her leitet sich Progressive Web App von Web Apps mit Progressive Enhancement ab. Aber wo liegt da die Innovation? Bei der Entwicklung einer Web App denkt man heute an große Frameworks wie Angular, React, Vue und neueste Browser APIs wie die Geolocation API und viele mehr. Das ist auch bei einer PWA alles einsetzbar, denn Achtung: Eine PWA unterliegt keinem Framework und schließt auch kein Framework aus. Die Limitierung besteht lediglich durch die Gegebenheiten des Browsers.

Progressive Enhancement, zu deutsch progressive Verbesserung, beschreibt den Content-First Ansatz. Ziel dieser Optimierung ist es, dass der First-Meaningful-Paint beim Aufbau einer Seite möglichst früh geschieht. Sprich Content zuerst und weitere Layer wie Skripte, Style und Multimedia Files, werden nach und nach, je nach Netzwerkverbindung geladen und aufgebaut. Das ist aber keine Neuheit, die im Zuge von PWAs entstanden ist, sondern ein Ergebnis der letzten Jahre der Webentwicklung, Suchmaschinen- und User Experience-Optimierung.

Zusammengefasst lässt sich sagen, der Begriff Progressive Web App weist nicht auf die wahre Innovation hin. Web Apps, moderne Browser APIs und progressiver Aufbau wurden nicht mit PWAs erfunden. Frances Berriman, einer der Mitbegründer bei Google geht sogar so weit zu sagen: “The name isn’t for you… The name is for your boss, for your investor, for your marketeer.” [5] 

Worin liegt die Innovation?

Um auf die wahre Innovation hinter PWAs zu kommen, müssen wir zunächst die aktuellen Probleme in der Bereitstellung von Web Apps und nativen Apps betrachten. Web Apps sind eine tolle Sache, aber auf der geschäftlichen Seite fragt man sich, wie man den Benutzer an den Service binden kann. Soll man den Benutzer dazu auffordern, Lesezeichen im Browser zu machen, Social Media Aktivitäten zu verfolgen oder soll man eine weitere App entwickeln, die im Store ausgeliefert wird? Das alles erfordert zusätzliche Motivation beim Benutzer, den Content oder Service zu konsumieren und, auch wenn kein Medienbruch erfolgt, liegt an jeder Stelle der Customer Journey eine kleine Abbruchrate (Bounce Rate) vor. Es gibt auch Hinweise die bestätigen, dass die Downloadzahlen aus den App Stores immer kleiner werden, wobei der Traffic im Internet weiter zunimmt [6]. Dort ist der User und dort will er auch abgeholt werden. Was ist also naheliegender, als den Content, den man sowieso schon über das Web bereitstellt, für den Kunden dauerhaft zur Verfügung zu stellen? Ohne überflüssige Zwischenschritte in der Customer Journey? Das lässt sich zwar mit Web Apps realisieren, aber wenn der Benutzer keine Internetverbindung hat, klingelt auch bei den Entwicklern nichts in der Kasse.
Auch native Apps bringen ihre Probleme auf der geschäftlichen Seite mit. Hohe Entwicklungskosten und straffe Anforderungen der Store Betreiber, sorgen regelmäßig für Frust und lange Nächte beim Release des nächsten Updates. Payment-Optionen werden vordiktiert, undurchsichtige Indexierungen der Store Einträge erlauben keine freien Produktplatzierungen und Marketing. Wie soll man da aus der Masse an Apps herausstechen und sein eigenes Produkt sinnvoll bewerben? Von den Gebühren die Apple und Google beim App-Kauf abkassieren, mal ganz abgesehen. Neben der undurchsichtigen Indexierung ist auch die Auffindbarkeit außerhalb der App Stores problematisch. Zwar lassen sich Apps inzwischen in Suchmaschinen auffinden, werden aber vom Content her nicht so von Web Crawler erfasst, wie herkömmliche Websites. Keine direkte Indexierung bedeutet eine lange Customer Journey bis ein Kunde das Produkt entdeckt und das bedeutet hohe Kosten. 

Diesen Punkten versucht eine PWA entgegenzuwirken. Eine PWA kann online und offline, barrierefreie konsumiert werden. Der Zwang einer App-Installation ist nicht erforderlich, der Kunde kann den Content zunächst über das Web auffinden und konsumieren und sich jederzeit impulsiv für eine App-Installation entscheiden. 

Technik & Funktionsweise

Eine PWA funktioniert grundsätzlich wie eine gewöhnliche Web App. Man kann jede Web App als Basis nehmen, erweitert um Manifest, Service Worker und App Icon. Wichtig zu wissen ist, dass eine PWA nur mit https funktioniert und sie sich auch nur installieren lässt, wenn die Verbindung über https gesichert wurde. Dieser Zwang ist ein willkommener Vorteil, der ein bisschen Sicherheit ins World Wide Web bringt. 

Die nachfolgende Übersicht zeigt einen schematischen Aufbau und Zusammenhänge. In den nachfolgenden Abschnitten schauen wir uns die einzelnen Elemente im Detail an.

Abb. 3: Funktionsweise und Aufbau von PWAs [9]


Manifest

Das Manifest liefert die, für die Installation der App, notwendigen Metadaten. Es muss per Link-Element in den Head des HTML-Dokuments eingebunden werden. In Json formatiert liefert es u.a.:

  • App Name
  • App Beschreibung
  • App Icon in versch. Auflösungen für versch. Endgeräte und Browser
  • Informationen bzgl. des Urhebers
  • App-Scope
  • Start Modus

Eine vollständige Liste aller mögliche Attribute findet sich hier:
https://developer.mozilla.org/de/docs/Web/Manifest

App Scope

Die Property “start_url” beschreibt den Scope der App innerhalb der Domain. Über diesen Parameter wird auch definiert welche Seite beim Start der App angezeigt werden soll.

Start Modus

Die Property “display” beschreibt den Start-Modus der App. Die nachfolgende Bilderreihe zeigt die Auswirkungen der einzelnen Optionen. Mit der Standalone-Option kann man den Look einer nativen App perfekt imitieren. Über den Parameter Theme Color lässt sich zusätzlich die Gestaltung der Statusleiste beeinflussen.

Abb. 4: Browser Modes [7]

Service Worker

Der Service Worker ist der Hintergrunddienst einer PWA. Er ist verwandt mit dem Web Worker, läuft in einem eigenen Thread und erlaubt keine direkte DOM-Manipulation, sondern nur die Kommunikation über eine definierte Schnittstellen. 

Er ist auch bei geschlossener Anwendung lauffähig, legt sich schlafen und erwacht bei eintreffenden Informationen! Mit seiner Hilfe wird eine PWA offlinefähig. Seine Aufgabe ist es, alle Requests die aus dem eigenen Scope ins Netzwerk geschickt werden, abzufangen und zu beurteilen, ob er mögliche Anfragen aus dem eigenen Cache beantworten kann oder nicht. Technisch betrachtet fungiert er quasi als Pseudo-Proxy. In welchem Umfang Requests ins Netzwerk geschickt werden oder aus dem eigenen Cache beantwortet werden, liegt im ermessen des Entwicklers. So ist über das Install-Event des Service Workers, dass bei App-Installation getriggert wird, ein vollständiger Download des App-Contents möglich, was die App damit gänzlich offlinefähig machen würde. Über die Wake-Up Funktion werden Push Notifications auf dem Endgerät ermöglicht, womit man der User Experience einer nativen App wieder einen großen Schritt näher kommen kann. 

Weitere Informationen und eine Übersicht von möglichen Events auf die gelauscht werden kann, findet man unter:
https://developer.mozilla.org/de/docs/Web/API/Service_Worker_API/
Using_Service_Workers


Skandal – Sind Service Worker die neuen Cookies?

Das eine App einen Hintergrunddienst benötigt, ist aus der nativen App- Entwicklung betrachtet, nichts ungewöhnliches. Async-Tasks, Services, Background Tasks, etc. sind jedem Android- oder iOS-Developer ein Begriff. In der Entwicklung von gewöhnlichen Websites (keine Web Apps), sind Hintergrunddienste allerdings eher selten von Bedarf. Der Benutzer weiß inzwischen durch Aufklärungsmaßnahmen, dass der Besuch einer Website in seinem Browser Spuren hinterlässt, sei es Cache, Cookies usw. ABER und jetzt kommt der Skandal: Viele Benutzer wissen nicht (!), dass ihr Browser ebenso durch Service Worker belastet wird, die sich wie eine Zecke in den Browser schleichen, jederzeit aus dem Schlaf erwecken lassen und die die Performance des ganzen Gerätes durch Hintergrunddienste beeinträchtigen können! Wenn man den Artikel bis hierher verfolgt hat, könnte man nun meinen, das Service Worker nur für PWAs eingesetzt werden, aber das Web war schon immer dafür bekannt, dass man sämtliche Tricks ausnutzt, die irgendwie möglich sind. Ich kann an dieser Stelle nur jedem Chrome-Benutzer, egal ob auf Mobile oder Desktop empfehlen, mit dem nachfolgenden Link zu überprüfen, wieviele Service Worker sich unwissend in den eigenen Browser geschlichen haben. Eine vergleichbare Schnittstelle zum überprüfen der registrierten Service Worker bieten andere Browser derzeit nicht an, obwohl sie sie unterstützen! Über Service Worker lässt sich beispielsweise das heimliche Crypto Mining auf Kosten von unwissenden Benutzern realisieren.

Check:  chrome://serviceworker-internals

Push Notifications

Eine Push Notification, die über eine installierte PWA gesendet wurde, lässt sich nicht von einer nativen Notification unterscheiden. Auch jede Referenz auf den zugrundeliegenden Browser wird verborgen. Notifications lassen sich über den Service Worker triggern, der wiederum von App oder Server dazu angestoßen wird.

Abb. 5: PWA Push Notifications vs. native Notifications [9]

Splash Screen

Um dem Start einer App eine bessere User Experience zu verpassen, hat man sich entschlossen, dass eine PWA mit einem Splash Screen startet, während im Hintergrund der Content aufgebaut wird. So wird auf geschickte Art und Weise performance suggeriert und langweilt den Benutzer nicht mit einem Whitescreen. Splash Screens lassen sich nicht an- oder ausschalten, aber customizen. Per Default sind App Icon und App Name (Android) gesetzt.

Abb. 6: Splash Screen auf Android (links) und iOS (rechts) [8]

Optimize & Debug

Wer eine PWA programmieren und das beste an Performance herauskitzeln will, der findet in den Developer Tools des Chrome Browsers das beste Hilfsmittel. Über die Audit-Tests startet der Browser auf Knopfdruck eine Reihe an Tests, die eine PWA in Bezug auf Vollständigkeit (PWA-Anforderungen), Performance, Best Practises, Accessibility und Semantik (SEO) hin bewertet. Auf einer Skala von 1-10 wird ein Scoring ermittelt und aufgelistet wo Verbesserungspotential besteht.

Abb. 7: Audits in der Chrome Developer Console [9]

Exkurs – Browser APIs

Um sich bei Funktionalität und User Experience einer nativen App anzunähern, liefern moderne Browser heute schon jede Menge APIs, die man vielleicht gar nicht kennt. Darunter auch einige hardwarenahe Schnittstellen, die häufig noch gar keinen Gebrauch finden, aber die Zukunft mitprägen können. Um sicherzustellen, dass entsprechende APIs auch schon in weit verbreiteten Browsern implementiert sind, bietet sich an, diese vor Implementierung, mit Hilfe des Can I Use – Services zu prüfen.

Eine Auswahl eher unbekannter APIs:

  • Sensors API
    • Ambient Light, Proximity, Accelerometer, Magnetometer, Gyroskop
  • Battery Manager API
  • Web Payments API
  • Gamepad API
  • Geolocation (GPS) API
  • Vibration API
  • Web Speech API (Text-To-Speech, Speech-To-Text, Grammar)
  • Bluetooth API
  • Push Notification API
  • USB Device API
  • WebVR API
  • Indexed Database API
  • File System API


PWA vs. Native

Wir wir bisher erfahren haben, ermöglichen moderne Browser schon mehr Features, wie man vielleicht vermuten mag. Wenn man betrachtet, dass PWAs erst seit 2018 von allen großen Browsern unterstützt werden, kann man schlussfolgern, dass das ganze Thema noch in den Kinderschuhen steckt. Aber bereits jetzt, durch die herausragende Performance-Steigerung mobiler Endgeräte in den letzten Jahren, sind tolle Anwendungen im mobile Web möglich, so dass native Apps aus Kostengründen wohl immer unattraktiver werden, sofern keine native Performance für das Produkt erforderlich ist. Auch der PWA-Standard wird sich in den nächsten Jahren weiterentwickeln und immer mehr Möglichkeiten bieten. Es bahnt sich vielleicht eine spannende Welle der Veränderungen an, die den Mobile-App-Markt durcheinander bringen könnte!

Zum Abschluss eine Übersichtsmatrix die zur Entscheidungsfindung hilfreich sein kann. Die meisten Punkte erhält die Umsetzungsart, die am besten abschneidet.

Web AppPWANative App
Speicherbedarf auf dem Endgerät◼️◼️◼️
Offlinefähigkeit◼️◼️◼️◼️
Auffindbarkeit in Suchmaschinen◼️◼️◼️◼️◼️
Installation, Updates, Wartung, Versionierung◼️◼️◼️◼️◼️
Performance, Ladezeiten◼️◼️◼️
Sicherheit(kann)◼️◼️(kann)
Entwicklungskosten◼️◼️◼️
Natürlicher Traffic◼️◼️◼️◼️◼️
Hardwarenahe Features◼️◼️◼️◼️
User Experience(kann)(kann)◼️◼️


In 10 Schritten zur ersten PWA

Hier noch einen Quickguide zur ersten Progressive Web App:

  1. Web App programmieren
  2. Sicher stellen, dass die Kommunikation zum Server ausschließlich über https läuft
  3. Web Manifest anlegen mit mindestens:
    • Scope
    • Start URL
    • App Icon und App Name
  4. Web Manifest im Head des HTML-Dokuments einbinden
  5. ServiceWorker.js (o.ä.) in root Folder der PWA anlegen
  6. Service Worker im JS der Web App registrieren
  7. ServiceWorker.js je nach Bedarf implementieren
  8. Mit Audits testen ob alle empfohlenen Qualitätskriterien einer PWA erreicht sind
  9. Deployen 🙂



Quellenverzeichnis

[1] Great examples of progressive web apps in one room
https://progressivewebapproom.com/
Zugegriffen am 05.08.2019, 22:08 Uhr

[2] Rio Run App von the Guardian,
https://riorun.theguardian.com/
Zugegriffen am 05.08.2019, 22:08 Uhr

[3] Wikipedia
https://en.wikipedia.org/wiki/Progressive_web_applications
Zugegriffen am 05.08.2019, 22:08 Uhr

[4] Welcoming Progressive Web Apps to Microsoft Edge and Windows 10
https://blogs.windows.com/msedgedev/2018/02/06/welcoming-progressive-web-apps-edge-windows-10/
Zugegriffen am 05.08.2019, 22:08 Uhr

[5] Naming Progressive Web Apps
https://fberriman.com/2017/06/26/naming-progressive-web-apps/
Zugegriffen am 05.08.2019, 22:08 Uhr

[6] Why Build Progressive Web Apps
https://developers.google.com/web/ilt/pwa/why-build-pwa
Zugegriffen am 05.08.2019, 22:08 Uhr

[7]  Progressive Web App Challenges
https://www.slideshare.net/grigs/progressive-web-app-challenges
Zugegriffen am 05.08.2019, 22:08 Uhr

[8] Progressive Web App Splash Screens
https://medium.com/@applification/progressive-web-app-splash-screens-80340b45d210
Zugegriffen am 05.08.2019, 22:08 Uhr

[9] Eigene Leistung