Offline first ist das neue mobile first - International PHP Conference
←
→
Transkription von Seiteninhalten
Wenn Ihr Browser die Seite nicht korrekt rendert, bitte, lesen Sie den Inhalt der Seite unten
Über mich Sebastian Springer • JavaScript Entwickler • aus München • bei MaibornWolff • https://github.com/sspringer82 • @basti_springer • Techstack: Node & React
PWA Progressive Web App • Schnell und zuverlässig: Startet schnell und bleibt schnell • Installierbar: Kann auf dem Zielsystem installiert werden • Mobile & Desktop: Verhält sich auf dem Zielsystem wie eine native App
Offline first Wie funktioniert die Applikation ohne Internet • Offline ist kein Ausnahmezustand • Benutzer können die Applikation (mit Einschränkungen) verwenden • Es findet reguläre Interaktion statt • Sobald die Verbindung wiederhergestellt ist, werden die Daten synchronisiert
Offline? Es gibt nicht nur schwarz und weiß • Keine Verbindung • Sehr langsame Verbindung • Keine Verbindung zum Server
Web App Manifest • JSON-Datei mit Metainformationen • Wird über ein link-Tag eingebunden • Enthält z.B. • Namen (kurz und lang) • Display - wie soll die Applikation angezeigt werden • Icons
Web App Manifest { "short_name": "Timetracker", "name": "Time tracking application", "icons": [ { "src": "favicon.ico", "sizes": "64x64 32x32 24x24 16x16", "type": "image/x-icon" },… ], "start_url": ".", "display": "standalone", "theme_color": "#000000", "background_color": "#ffffff" }
Service Workers Herbert Käfer / pixelio.de
Service Worker Hintergrundprozess im Browser • Wird bei Bedarf aktiviert • Features: Caching, Push Notifications, Background Sync • Kein Zugriff auf das DOM • Kommunikation über postMessage • Persistenz: IndexedDB
Service Workers Frontend Applikation Browser Service Worker HTTP Server Backend
Service Workers HTTPS only (oder localhost)
Service Workers Installed/ Parsed Installing Activating Activated Redundant Waiting
Service Workers • Parsed: initiales Einlesen des Scripts. SW kann registriert werden. • Installing: SW wird installiert. Hier können Dateien gecached werden. • Installed/Waiting: SW ist erfolgreich installiert, hat aber noch keine Kontrolle über die Applikation. Hier kann der Benutzer informiert werden. • Activating: SW wird aktiviert. Hier können Caches aufgeräumt werden. • Active: Der SW ist aktiv und kontrolliert die Applikation. • Redundant: Installation oder Aktivierung ist fehlgeschlagen oder es gibt einen neueren SW.
Service Workers Beim ersten Aufruf wird der SW zwar installiert aber noch nicht aktiviert. Achtung: Updates werden eventuell zeitverzögert angewendet.
Service Workers
Service Workers https://serviceworke.rs/
Service Workers
Workbox JavaScript Library for adding offline support to web apps • Basis für Create React App • Plugin-Schnittstellen für Erweiterungen verfügbar • Verschiedene Caching-Strategien
Workbox import {precacheAndRoute} from 'workbox-precaching'; import {registerRoute} from 'workbox-routing'; import {CacheFirst} from 'workbox-strategies'; precacheAndRoute(self.__WB_MANIFEST); registerRoute(/^https:\/\/example.com\/assets/, new CacheFirst({ cacheName: 'static-assets', matchOptions: { ignoreVary: true, }, plugins: [new ExpirationPlugin({ maxEntries: 500, maxAgeSeconds: 63072e3, purgeOnQuotaError: true, }), new CacheableResponsePlugin({ statuses: [0, 200] })] }));
Workbox Cache Strategien • Stale-While-Revalidate: Cache First und paralleles Cache Update • Cache First (Cache Falling Back to Network) • Network First (Network Falling Back to Cache) • Network Only Cache First • Cache Only https://developers.google.com/web/tools/workbox/modules/workbox-strategies
IndexedDB Rainer Sturm / pixelio.de
IndexedDB Auf die IndexedDB kann aus dem Haupt- und den Worker-Prozessen zugegriffen werden, um Daten zu speichern und zu lesen. Statt Daten direkt zum Server zu senden oder sie von dort zu lesen, kann die IndexedDB als Zwischenschritt verwendet werden.
IndexedDB
Dexie.js const db = new Dexie(‘TodoList'); db.version(1).stores({ todos: '++id, title' }); await db.todos .where('title') .equals('Go to work') .toArray(); await db.todos.add({ title: 'Go to sleep', status: 'open', });
Das Standardverhalten
Das Standardverhalten Die out-of-the-box PWA von React • Vorkonfigurierter Service Worker mit “cache-first” • Service Worker ist standardmäßig deaktiviert • Service Worker kann nur im production Build aktiviert werden • Template für Manifestdatei
Das Standardverhalten Die out-of-the-box PWA von React • src/index.tsx: serviceWorker.unregister(); => serviceWorker.register(); • npm run build • npx http-server build
Das Standardverhalten Installierbar
API Calls
API Calls Was ist mit dynamischen Anfragen? • Anfragen an eine Web-API • Schreibende Zugriffe • Lesende Zugriffe • Daten müssen für den offline-Betrieb zwischengespeichert werden • Anfragen müssen offline abgefangen werden • Sobald die Verbindung wiederhergestellt ist, müssen die Abfragen abgespielt werden
2 Lösungsmöglichkeiten • Im Serviceworker • In der Applikation
Offlinefähigkeit im Service Worker
Offlinefähigkeit im Service Worker • Der Serviceworker fängt die Anfragen ab • Sie werden entweder an den Server weitergeleitet • Oder direkt beantwortet • Die Steuerung der Offlinefähigkeit erfolgt im JavaScript-Code des Service Workers • Die IndexedDB wird als Persistenzschicht verwendet
Offlinefähigkeit im Service Worker self.addEventListener('fetch', function(event) { if (event.request.url.includes('/items')) { if (event.request.method === 'GET') { event.respondWith(async () => { const items = await itemModel.getAll(); await itemModel.store(items); fetchHelper.createResponse(items); }); } else if(event.request.method === 'POST') { ... } } });
Offlinefähigkeit in der Applikation
Offlinefähigkeit in der Applikation • Die Applikation entscheidet, ob eine Anfrage an den Server gesendet wird • Alle lesenden Anfragen werden automatisch in der IndexedDB zwischengespeichert • Ist der Server nicht erreichbar, wird lokal zwischengespeichert • Sobald der Server verfügbar ist, wird synchronisiert • Die Applikation ist Offline-First implementiert und jederzeit offline arbeitsfähig
Offlinefähigkeit in der Applikation async function loadLogs() { try { const response = await axios.get('http://localhost:3001/logs'); if (!response) { throw new Error(NETWORK_ERROR); } db.table('items').clear(); db.table('items').bulkAdd(response.data); setLogs(data); } catch (e) { if (isNetworkError(e)) { const data = await db.table('items').toArray(); setLogs(data); } else { throw new Error('Whoops '); } } }
And the winner is…
And the winner is… Vergleich der beiden Ansätze • Offlinefähigkeit im Service Worker • Die Applikation weiß nichts von Offlinefähigkeit • Es existiert eine zweite (Schatten-) Applikation • Offlinefähigkeit in der Applikation • Die Applikation ist komplexer • Die Offlinefähigkeit kann innerhalb der Applikation getestet werden • Der Serviceworker übernimmt nur statisches Caching
Persistenz
Serverseitig Umgang mit Datensynchronisierung • Was passiert bei neuen Datensätze, die offline erzeugt wurden? • Wie können Konflikte aufgelöst werden?
Neue Datensätze • Das Frontend vergibt im Offline-Modus temporäre IDs für neue Datensätze • Änderungen und Löschungen werden im Offline-Modus verfolgt • Änderungen anwenden und nur ein Objekt synchronisieren • Änderungen als Events serverseitig abspielen (Eventsourcing) • Werden die Daten zum Server gesendet, wird die temporäre ID ersetzt
Neue Datensätze Client New Change Change Sync ID: c1 ID: c1 ID: c1 No Connection Connection Server New Change Change ID: 42 ID: 42 ID: 42
Konflikte
Konflikte • Im Multiuser-Betrieb versuchen mehrere Benutzer schreibend auf eine Ressource zuzugreifen • Ist mindestens ein Benutzer offline, entsteht ein potenzieller Konflikt • Konflikte müssen aufgelöst werden, um Inkonsistenzen zu vermeiden
Strategien zur Konfliktlösung • Änderungen mit Konflikten abweisen (first write wins) • Änderungen überschreiben (last write wins) • Automatisches zusammenführen (unterschiedliche Felder werden überschrieben) • Manuelles zusammenführen: Der Benutzer muss den Konflikt manuell auflösen
Noch eine Ebene weiter…
Zentrales Statemanagement Server Async Middleware Action Action Dispatcher Store View
Fragen? …dann wäre jetzt ein guter Zeitpunkt Rainer Sturm / pixelio.de
Kontakt Sebastian Springer sebastian.springer@maibornwolff.de MaibornWolff GmbH Theresienhöhe 13 80339 München @basti_springer https://github.com/sspringer82
Sie können auch lesen