Was das Bulletin-Team bei der Entwicklung einer PWA über Servicemitarbeiter gelernt hat.
Dies ist der erste einer Reihe von Blog-Posts zu den Lehren, die das Google Bulletin-Team aus der Erstellung einer externen PWA gezogen hat. In diesen Beiträgen werden wir einige der Herausforderungen, denen wir gegenüberstehen, die Ansätze, die wir zur Überwindung dieser Herausforderungen verfolgen, und allgemeine Tipps zur Vermeidung von Betrug vorstellen. Dies ist keineswegs eine vollständige Übersicht über die PWAs. Ziel ist es, die Erkenntnisse aus den Erfahrungen unseres Teams zu teilen.
In diesem ersten Beitrag werden wir zunächst einige allgemeine Informationen behandeln und dann auf alles eingehen, was wir über Servicemitarbeiter gelernt haben.
Das Bulletin wurde 2019 wegen mangelnder Produkt- / Marktanpassung geschlossen. Unterwegs haben wir noch viel über PWAs gelernt!
Hintergrund
Das Bulletin befand sich von Mitte 2017 bis Mitte 2019 in aktiver Entwicklung.
Warum wir uns für den Bau einer PWA entschieden haben
Bevor wir uns mit dem Entwicklungsprozess befassen, wollen wir untersuchen, warum das Erstellen einer PWA eine attraktive Option für dieses Projekt war:
- Fähigkeit, schnell zu iterieren. Besonders wertvoll, da das Bulletin in mehreren Märkten getestet werden würde.
- Einzelne Codebasis. Unsere Benutzer waren ungefähr gleichmäßig zwischen Android und iOS aufgeteilt. Eine PWA bedeutete, dass wir eine einzige Webanwendung erstellen konnten, die auf beiden Plattformen funktioniert. Dies erhöhte die Geschwindigkeit und Wirkung des Teams.
- Schnell und unabhängig vom Benutzerverhalten aktualisiert. PWAs können automatisch aktualisiert werden, wodurch die Anzahl veralteter Clients in freier Wildbahn verringert wird. Mit einer sehr kurzen Migrationszeit für Kunden konnten wir wichtige Änderungen am Backend vornehmen.
- Es lässt sich problemlos in Ihre eigenen Anwendungen und Anwendungen von Drittanbietern integrieren. Solche Integrationen waren Voraussetzung für die Anwendung. Bei einer PWA bedeutete dies oft, einfach eine URL zu öffnen.
- Die Reibung bei der Installation einer App wurde beseitigt.
Unser Rahmen
Für Bulletin verwenden wir Polymer, aber jedes moderne, gut unterstützte Framework wird es tun.
Was wir über Servicemitarbeiter gelernt haben
Sie können keine PWA ohne eine haben Servicemitarbeiter. Servicemitarbeiter bieten Ihnen viel Leistung, z. B. erweiterte Caching-Strategien, Offline-Funktionen, Hintergrundsynchronisierung und vieles mehr. Während Servicemitarbeiter eine gewisse Komplexität hinzufügen, haben wir festgestellt, dass ihre Vorteile die zusätzliche Komplexität überwiegen.
Generieren Sie es, wenn Sie können
Vermeiden Sie es, ein Service Worker-Skript von Hand zu schreiben. Das manuelle Schreiben von Servicemitarbeitern erfordert das manuelle Verwalten zwischengespeicherter Ressourcen und das Umschreiben der Logik, die den meisten Servicemitarbeiterbibliotheken gemeinsam ist, z Arbeitsbox.
Aufgrund unseres internen Tech-Stacks konnten wir jedoch keine Bibliothek zum Generieren und Verwalten unserer Servicemitarbeiter verwenden. Unsere folgenden Erkenntnisse werden dies manchmal widerspiegeln. Weitere Informationen finden Sie unter Probleme für nicht generierte Servicemitarbeiter.
Nicht alle Bibliotheken sind mit Servicemitarbeitern kompatibel
Einige JS-Bibliotheken gehen davon aus, dass sie nicht wie erwartet funktionieren, wenn sie von einem Servicemitarbeiter ausgeführt werden. Zum Beispiel unter der Annahme Fenster
oder Dokument
verfügbar sind oder eine API verwenden, die Servicemitarbeitern nicht zur Verfügung steht (XMLHttpRequest
, lokaler Speicher usw.). Stellen Sie sicher, dass die für Ihre Anwendung erforderlichen kritischen Bibliotheken von Servicemitarbeitern unterstützt werden. Für diese spezielle PWA wollten wir verwenden
gapi.js für die Authentifizierung, aber sie waren nicht in der Lage, dies zu tun, weil es keine Servicemitarbeiter unterstützte. Bibliotheksautoren sollten auch unnötige Annahmen zum JavaScript-Kontext reduzieren oder eliminieren, wann immer dies möglich ist, um Anwendungsfälle von Service Workern zu unterstützen, z. B. das Vermeiden inkompatibler Service Worker-APIs und das Vermeiden des globalen Status.
Vermeiden Sie den Zugriff auf IndexedDB während der Initialisierung
Nicht lesen IndexedDB Während Sie Ihr Service Worker-Skript initialisieren, geraten Sie möglicherweise in diese unerwünschte Situation:
- Der Benutzer hat eine Webanwendung mit IndexedDB (IDB) Version N.
- Eine neue Webanwendung ist in der N + 1-Version der IDB enthalten
- Der Benutzer besucht PWA, wodurch der Download eines neuen Servicemitarbeiters ausgelöst wird
- Der neue Servicemitarbeiter liest vor der Registrierung aus der IDB
Installieren
Ereignishandler, der einen BID-Aktualisierungszyklus aktiviert, um von N nach N + 1 zu gelangen - Da der Benutzer einen alten Client mit Version N hat, bleibt der Aktualisierungsprozess für Service Worker hängen, da aktive Verbindungen zur vorherigen Version der Datenbank noch offen sind
- Der Servicemitarbeiter hängt und wird nie installiert
In unserem Fall ist der Cache bei der Installation des Service Workers ungültig. Wenn der Service Worker also nie installiert wurde, haben die Benutzer die aktualisierte Anwendung nie erhalten.
Mach es hart
Obwohl Service Worker-Skripte im Hintergrund ausgeführt werden, können sie auch jederzeit beendet werden, selbst wenn sie sich mitten in E / A-Vorgängen befinden (Netzwerk, IDB usw.). Jeder lange laufende Prozess sollte jederzeit fortgesetzt werden können.
Bei einem Synchronisierungsprozess, bei dem große Dateien auf den Server hochgeladen und im BID gespeichert wurden, bestand unsere Lösung für unterbrochene Teil-Uploads darin, das wiederaufnehmbare System aus unserer internen Upload-Bibliothek zu nutzen und die wiederaufnehmbare Upload-URL vor dem Hochladen im BID zu speichern und verwenden Sie diese URL, um einen Upload fortzusetzen, wenn er beim ersten Mal nicht abgeschlossen wurde. Außerdem wurde der Status vor einer langen E / A-Operation in IDB gespeichert, um anzugeben, wo wir uns für jeden Datensatz im Prozess befanden.
Hängen Sie nicht vom globalen Staat ab
Da Servicemitarbeiter in einem anderen Kontext existieren, sind viele Symbole, die Sie möglicherweise erwarten, nicht vorhanden. Ein Großteil unseres Codes lief auf beiden Fenster
Kontext sowie einen Service Worker-Kontext (wie Registrierung, Flags, Synchronisierung usw.). Der Code sollte gegenüber den von Ihnen verwendeten Diensten, wie z. B. lokalem Speicher oder Cookies, defensiv sein. Sie können verwenden
globalThis
auf das globale Objekt in einer Weise zu verweisen, die in allen Kontexten funktioniert. Verwenden Sie auch in globalen Variablen gespeicherte Daten sparsam, da nicht garantiert werden kann, wann das Skript beendet und der Status gelöscht wird.
Lokale Entwicklung
Ein wichtiger Bestandteil der Servicemitarbeiter ist das lokale Zwischenspeichern von Ressourcen. Während der Entwicklung ist dies jedoch die Gegenteil als Sie möchten, insbesondere wenn Aktualisierungen träge durchgeführt werden. Sie möchten den Server Worker weiterhin installieren, damit Sie Probleme damit debuggen oder mit anderen APIs wie Hintergrundsynchronisierung oder Benachrichtigungen arbeiten können. In Chrome können Sie dies über Chrome DevTools erreichen, indem Sie die Option aktivieren Bypass für Netzwerk KontrollkästchenAnfrage Panel> Servicemitarbeiter Panel) zusätzlich zur Aktivierung der Cache deaktivieren Kontrollkästchen in der Netz Bedienfeld zum Deaktivieren des Cache-Speichers. Um mehr Browser abzudecken, haben wir uns für eine andere Lösung entschieden, indem wir ein Flag zum Deaktivieren des Caching in unserem Service Worker eingefügt haben, das in Entwickler-Builds standardmäßig aktiviert ist. Dies stellt sicher, dass Entwickler immer ihre neuesten Änderungen erhalten, ohne Probleme beim Zwischenspeichern zu haben. Es ist wichtig, die einzubeziehen Cache-Kontrolle: kein Cache
Header auch, um zu verhindern, dass der Browser Assets zwischenspeichert.
Leuchtturm
Leuchtturm bietet eine Reihe nützlicher Debugging-Tools für PWAs. Es scannt eine Website und generiert Berichte zu PWA, Leistung, Zugänglichkeit, SEO und anderen Best Practices.
Wir empfehlen Lighthouse in kontinuierlicher Integration ausführen um Sie wissen zu lassen, wenn Sie keines der Kriterien für eine PWA erfüllen. Dies ist uns tatsächlich einmal passiert, als der Servicemitarbeiter nicht installiert hat und wir vorher keinen Produktionsschub bemerkt haben. Lighthouse als Teil unseres CI zu haben, hätte dies verhindert.
Umfassen Sie kontinuierliche Lieferung
Da Servicemitarbeiter automatisch aktualisieren können, können Benutzer Aktualisierungen nicht einschränken. Dies reduziert die Anzahl veralteter Kunden in freier Wildbahn erheblich. Als der Benutzer unsere App öffnete, bediente der Servicemitarbeiter den alten Kunden, während er den neuen Kunden träge herunterlud. Sobald der neue Client heruntergeladen wurde, wird der Benutzer aufgefordert, die Seite zu aktualisieren, um auf neue Funktionen zugreifen zu können. Selbst wenn der Benutzer diese Anforderung ignorierte, erhielt er beim nächsten Aktualisieren der Seite die neue Version des Clients. Infolgedessen ist es für einen Benutzer ziemlich schwierig, Aktualisierungen auf die gleiche Weise wie für native Anwendungen abzulehnen.
Mit einer sehr kurzen Migrationszeit für Kunden konnten wir wichtige Änderungen am Backend vornehmen. Wir geben den Benutzern in der Regel einen Monat Zeit, um auf neuere Clients zu aktualisieren, bevor größere Änderungen vorgenommen werden. Da die Anwendung veraltet funktionieren würde, könnten ältere Clients in freier Wildbahn existieren, wenn der Benutzer die Anwendung längere Zeit nicht geöffnet hätte. Unter iOS sind Servicemitarbeiter
nach ein paar Wochen vertrieben
Dieser Fall tritt also nicht auf. Für Android kann dieses Problem behoben werden, wenn es nicht veröffentlicht wird, während es veraltet ist, oder wenn der Inhalt nach einigen Wochen manuell abgelaufen ist. In der Praxis stoßen wir nie auf Probleme mit veralteten Kunden. Wie streng ein Team hier sein möchte, hängt von Ihrem spezifischen Anwendungsfall ab. PWAs bieten jedoch erheblich mehr Flexibilität als native Apps.
Erhalten Sie Cookie-Werte in einem Servicemitarbeiter
Manchmal ist es erforderlich, im Kontext eines Servicemitarbeiters auf Cookie-Werte zuzugreifen. In unserem Fall mussten wir auf die Cookie-Werte zugreifen, um ein Token zur Authentifizierung der ursprünglichen API-Anforderungen zu generieren. In einem Service Worker mögen synchrone APIs document.cookies
Sind nicht verfügbar. Sie können vom Service Worker jederzeit eine Nachricht an aktive (mit Fenstern versehene) Clients senden, um Cookie-Einstellungen anzufordern. Der Service Worker wird jedoch möglicherweise im Hintergrund ausgeführt, ohne dass Clients mit Fenstern verfügbar sind, z. B. während einer Synchronisierung im Hintergrund. Um dies zu beheben, haben wir auf unserem Frontend-Server einen Endpunkt erstellt, der einfach den Wert des Cookies an den Client zurückgibt. Der Servicemitarbeiter hat eine Netzwerkanforderung an diesen Endpunkt gesendet und die Antwort gelesen, um die Cookie-Werte abzurufen.
Mit dem Start der
Cookie-Store-APIDiese Problemumgehung sollte für Browser, die sie unterstützen, nicht mehr erforderlich sein, da sie asynchronen Zugriff auf Browser-Cookies bietet und direkt vom Servicemitarbeiter verwendet werden kann.
Fallstricke für nicht generierte Servicemitarbeiter
Stellen Sie sicher, dass sich das Service Worker-Skript ändert, wenn Sie statische zwischengespeicherte Dateien ändern
Ein gängiges PWA-Muster besteht darin, dass ein Servicemitarbeiter alle statischen Anwendungsdateien während der Installation installiert
Installieren
Phase, in der Clients für alle nachfolgenden Besuche direkt auf den Caching-API-Cache zugreifen können. Service Worker werden nur installiert, wenn der Browser feststellt, dass sich das Service Worker-Skript auf irgendeine Weise geändert hat. Daher mussten wir sicherstellen, dass sich die Service Worker-Skriptdatei beim Ändern einer zwischengespeicherten Datei auf irgendeine Weise geändert hat. Wir haben dies manuell getan, indem wir einen Hash der statischen Ressourcendateien in unser Service Worker-Skript eingebettet haben, sodass jede Version eine andere Service Worker-JavaScript-Datei erstellt hat. Service-Worker-Bibliotheken wie
Arbeitsbox Automatisieren Sie diesen Prozess für Sie.
Unit Exam
Die Service Worker-APIs fügen dem globalen Objekt Ereignis-Listener hinzu. Zum Beispiel:
selbst.addEventListener('fetch', (evt) => evt.respondWith(holen('/foo')));
Dies kann schwierig zu testen sein, da Sie den Ereignisauslöser, das Ereignisobjekt, simulieren und auf das warten müssen Antworten mit ()
Rückruf, und warten Sie dann auf das Versprechen, bevor Sie das Ergebnis endgültig bestätigen. Eine einfachere Möglichkeit, dies zu strukturieren, besteht darin, die gesamte Implementierung an eine andere Datei zu delegieren, die einfacher zu testen ist.
importieren fetchHandler desde './fetch_handler.js';
selbst.addEventListener('fetch', (evt) => evt.respondWith(fetchHandler(evt)));
Aufgrund der Schwierigkeiten beim Unit-Test eines Service-Worker-Skripts haben wir das Kern-Service-Worker-Skript so einfach wie möglich gehalten und den größten Teil der Implementierung in andere Module unterteilt. Da es sich bei diesen Dateien nur um Standard-JS-Module handelte, konnten sie mit Standard-Testbibliotheken einfacher auf Einheitentests getestet werden.
Seien Sie gespannt auf Teil 2 und 3
In den Teilen 2 und 3 dieser Reihe werden wir uns mit Medienverwaltung und iOS-spezifischen Themen befassen. Wenn Sie uns mehr über das Erstellen einer PWA bei Google fragen möchten, besuchen Sie unsere Autorenprofile, um herauszufinden, wie Sie mit uns Kontakt aufnehmen können: