Eine Anwendungs-Shell ist der minimale HTML-, CSS- und JavaScript-Code, der eine Benutzeroberfläche unterstützt. Die Anwendungs-Shell sollte:
- schnell geladen werden.
- im Cache gespeichert werden
- Inhalte dynamisch anzeigen
Eine Anwendungs-Shell ist das Geheimnis für eine zuverlässig gute Leistung. Stellen Sie sich den Shell Ihrer App als das Code-Bundle vor, das Sie in einem App-Shop veröffentlichen würden, wenn Sie eine native App entwickeln. Es ist die Last, die zum Starten erforderlich ist, aber möglicherweise nicht die ganze Geschichte. Die Benutzeroberfläche bleibt lokal und Inhalte werden dynamisch über eine API abgerufen.
Hintergrund
Im Artikel Progressive Web Apps von Alex Russell wird beschrieben, wie sich eine Web-App schrittweise durch die Nutzung und die Einwilligung der Nutzer ändern kann, um eine ähnliche Nutzererfahrung wie bei einer nativen App zu bieten, einschließlich Offlineunterstützung, Push-Benachrichtigungen und der Möglichkeit, zur Startseite hinzugefügt zu werden. Das hängt stark von den Funktionen und Leistungsvorteilen von Dienstworkern und ihren Caching-Funktionen ab. So können Sie sich auf die Geschwindigkeit konzentrieren und Ihren Webanwendungen dieselben sofortigen Ladezeiten und regelmäßigen Updates bieten, die Sie von nativen Anwendungen gewohnt sind.
Um diese Funktionen optimal nutzen zu können, müssen wir unsere Websites neu denken: die Anwendungs-Shell-Architektur.
Sehen wir uns an, wie Sie Ihre App mit einer Service Worker-gestützten Anwendungs-Shell-Architektur strukturieren. Wir sehen uns sowohl das client- als auch das serverseitige Rendering an und stellen Ihnen ein End-to-End-Beispiel zur Verfügung, das Sie gleich ausprobieren können.
Zur Veranschaulichung zeigt das Beispiel unten die erste Ladezeit einer App mit dieser Architektur. Unten auf dem Bildschirm wird die Meldung „App ist offline verfügbar“ angezeigt. Wenn später ein Update für die Shell verfügbar wird, können wir den Nutzer bitten, die neue Version zu verwenden.
Was sind Service Worker?
Ein Service Worker ist ein Script, das unabhängig von Ihrer Webseite im Hintergrund ausgeführt wird. Er reagiert auf Ereignisse, einschließlich Netzwerkanfragen von Seiten, die er ausliefert, und Push-Benachrichtigungen von Ihrem Server. Ein Dienst-Worker hat eine absichtlich kurze Lebensdauer. Sie wird aktiviert, wenn ein Ereignis eintritt, und läuft nur so lange, wie es für die Verarbeitung des Ereignisses erforderlich ist.
Im Vergleich zu JavaScript in einem normalen Browserkontext haben Service Worker auch eine begrenzte Anzahl von APIs. Das ist Standard für Worker im Web. Ein Dienst-Worker kann nicht auf das DOM zugreifen, aber z. B. auf die Cache API und Netzwerkanfragen mit der Fetch API stellen. Die IndexedDB API und postMessage() können auch für die Datenspeicherung und die Nachrichtenübermittlung zwischen dem Service Worker und den von ihm gesteuerten Seiten verwendet werden. Push-Ereignisse, die von Ihrem Server gesendet werden, können die Notification API aufrufen, um das Nutzer-Engagement zu erhöhen.
Ein Service Worker kann Netzwerkanfragen abfangen, die von einer Seite gesendet werden (wodurch ein Abrufereignis auf dem Service Worker ausgelöst wird), und eine Antwort zurückgeben, die aus dem Netzwerk oder aus einem lokalen Cache abgerufen oder sogar programmatisch erstellt wurde. Es ist im Grunde ein programmierbarer Proxy im Browser. Das Tolle daran ist, dass es für die Webseite unabhängig davon, woher die Antwort kommt, so aussieht, als wäre kein Service Worker beteiligt.
Weitere Informationen zu Dienstmitarbeitern finden Sie in der Einführung in Dienstmitarbeiter.
Leistungsvorteile
Service Worker sind leistungsstark für das Offline-Caching, bieten aber auch erhebliche Leistungsvorteile in Form des sofortigen Ladens bei wiederholten Besuchen Ihrer Website oder Webanwendung. Sie können die Anwendungs-Shell im Cache speichern, damit sie offline funktioniert, und die Inhalte mit JavaScript ausfüllen.
So können Sie bei wiederholten Besuchen aussagekräftige Pixel auf dem Bildschirm ohne das Netzwerk erzielen, auch wenn Ihre Inhalte letztendlich von dort stammen. Stellen Sie sich vor, dass Symbolleisten und Karten sofort angezeigt und der Rest der Inhalte dann schrittweise geladen wird.
Um diese Architektur auf echten Geräten zu testen, haben wir unser Beispiel für eine Anwendungs-Shell auf WebPageTest.org ausgeführt. Die Ergebnisse finden Sie unten.
Test 1: Test über Kabel mit einem Nexus 5 mit Chrome Dev
Für die erste Ansicht der App müssen alle Ressourcen aus dem Netzwerk abgerufen werden.Eine sinnvolle Darstellung ist erst nach 1,2 Sekunden möglich. Dank des Service Worker-Cachings wird beim wiederholten Besuch die Seite in 0, 5 Sekunden vollständig gerendert und geladen.
Test 2: Tests mit 3G auf einem Nexus 5 mit Chrome Dev
Wir können unser Beispiel auch mit einer etwas langsameren 3G-Verbindung testen. Diesmal dauert es beim ersten Besuch 2,5 Sekunden, bis die Inhalte weitgehend gezeichnet sind. Das Laden der Seite dauert 7,1 Sekunden. Mit dem Service Worker-Caching wird beim wiederholten Besuch eine sinnvolle Darstellung erreicht und das Laden ist in 0, 8 Sekunden abgeschlossen.
Andere Ansichten zeichnen ein ähnliches Bild. Vergleichen Sie die 3 Sekunden, die für die erste aussagekräftige Darstellung in der Anwendungs-Shell benötigt werden:
auf 0,9 Sekunden, wenn dieselbe Seite aus dem Service Worker-Cache geladen wird. So sparen unsere Endnutzer über zwei Sekunden.
Mit der Anwendungs-Shell-Architektur sind ähnliche und zuverlässige Leistungssteigerungen für Ihre eigenen Anwendungen möglich.
Müssen wir die Struktur von Apps überdenken, wenn wir Service Worker verwenden?
Service Worker erfordern einige subtile Änderungen an der Anwendungsarchitektur. Anstatt die gesamte Anwendung in einen HTML-String zu quetschen, kann es von Vorteil sein, AJAX zu verwenden. Hier haben Sie eine Shell (die immer im Cache gespeichert ist und immer ohne Netzwerk gestartet werden kann) und Inhalte, die regelmäßig aktualisiert und separat verwaltet werden.
Die Auswirkungen dieser Aufteilung sind enorm. Beim ersten Besuch können Sie Inhalte auf dem Server rendern und den Service Worker auf dem Client installieren. Bei nachfolgenden Besuchen müssen Sie nur Daten anfordern.
Was ist mit der progressiven Verbesserung?
Service Worker werden derzeit nicht von allen Browsern unterstützt. Die Architektur der Anwendungs-Content-Shell verwendet jedoch progressive Verbesserungen, damit alle auf die Inhalte zugreifen können. Nehmen wir zum Beispiel unser Beispielprojekt.
Unten sehen Sie die Vollversion, die in Chrome, Firefox Nightly und Safari gerendert wurde. Ganz links sehen Sie die Safari-Version, bei der die Inhalte ohne einen Service Worker auf dem Server gerendert werden. Rechts sehen wir die Chrome- und Firefox-Nightly-Versionen, die von Service Workern unterstützt werden.
Wann ist es sinnvoll, diese Architektur zu verwenden?
Die Anwendungs-Shell-Architektur eignet sich am besten für dynamische Apps und Websites. Wenn Ihre Website klein und statisch ist, benötigen Sie wahrscheinlich keine Anwendungs-Shell und können die gesamte Website einfach in einem Service Worker-oninstall-Schritt im Cache speichern. Verwenden Sie den Ansatz, der für Ihr Projekt am sinnvollsten ist. Einige JavaScript-Frameworks empfehlen bereits, die Anwendungslogik von den Inhalten zu trennen, was die Anwendung dieses Musters vereinfacht.
Gibt es bereits Produktions-Apps, in denen dieses Muster verwendet wird?
Die Anwendungs-Shell-Architektur ist mit nur wenigen Änderungen an der Benutzeroberfläche Ihrer gesamten Anwendung möglich und hat sich für große Websites wie die I/O 2015 Progressive Web App von Google und Google Inbox bewährt.
Offline-Anwendungs-Shells bieten erhebliche Leistungsvorteile und werden auch in der offlinefähigen Wikipedia-App von Jake Archibald und in der progressiven Webanwendung Flipkart Lite gut veranschaulicht.