Stephan Böni - Service Worker Cache

Service Worker Cache-Update

Service Worker Cache-Update

Während Service Worker und PWAs zu Standards moderner Webanwendungen werden, ist das Ressourcen-Caching komplexer als je zuvor. In diesem Beitrag werden wir eine Variante des Cache-Updates behandeln.

Cache zuerst, sofern er aktuell ist

Analog zum Browser-Cache ist die Strategie, zuerst im eigenen Cache nach der gefragten Ressource zu suchen, für die meisten Anwendungsfälle passend. In der Caching-Strategie haben wir auf dieses Szenario aufgebaut und die Kaskade vervollständigt.

Wenn die Ressource also bereits im Cache ist, wird sie von dort gezogen. Im Normalfall ist das korrekt. Nur wenn wir am Server die Ressource aktualisieren, bekommt der Client dies erst nach Ablauf des Caches mit, also spätestens in 90 Tagen.

Bei kleinen und meist statischen Websites, reicht es, wenn du bei Neuerungen die Cache-Version, des Service Workers erhöhst, also aus const cacheName = 'v1' ein const cacheName = 'v2' machst. Dadurch wird der Client angewiesen, den Cache gesamtheitlich neu zu bilden.

Das reicht dir nicht? Dann ist es Zeit für eine Cache-Update-Strategie.

Veralteter Cache löschen

Beim Installieren des Service Workers fragen wir den Server nach einer Liste von aktualisierten Ressourcen und löschen diese aus dem Cache.

service-worker.js // Call Install Event self.addEventListener('install', event => { // cache offline page event.waitUntil( (async () => { const cache = await caches.open(cacheName); // setting {cache: 'reload'} in the new request ensures that the // response isn't fulfilled from the HTTP cache; i.e., it will be // from the network. await cache.add(new Request(offlineUrl, { cache: 'reload' })); // clear cache for modified files await fetch('/includes/update.php') .then((response) => { if (!response.ok) { throw new Error('Network response was not ok'); } return response.json(); }) .then((fileList) => { for (file of fileList) { cache.delete(file); } }) })() ); // force the waiting service worker to become the active service worker self.skipWaiting(); });

Der Server liefert in unserem Beispiel ein JSON-Objekt eine Liste aller Dateien, die neuer als die service-worker.js sind. Wir gehen dabei also davon aus, dass mit der letzten Änderung am Service Worker der Cache-Name aktualisiert wurde.

update.php <?PHP // get last modification time of service worker $info = new SplFileInfo('../service-worker.js'); $SWmTime = date('YmdHis', $info->getMTime()); // generate list of newer files $dir_iterator = new RecursiveDirectoryIterator('..'); $iterator = new RecursiveIteratorIterator($dir_iterator, RecursiveIteratorIterator::SELF_FIRST); $updated = array(); foreach ($iterator as $file) { if (($file->isFile()) && (date('YmdHis', $file->getMTime()) > $SWmTime)) { array_push($updated, str_replace('index.php', '', substr($file->getPathname(), 2))); } } // return file list as json if(isset($_SERVER['HTTP_ORIGIN'])) { header("Access-Control-Allow-Origin: {$_SERVER['HTTP_ORIGIN']}"); header('Access-Control-Allow-Credentials: true'); header('Access-Control-Max-Age: 86400'); } header('Content-Type: application/json; charset=utf-8'); echo json_encode($updated); ?>

Das PHP-Script passt so für meine Website. Vermutlich musst du es noch für deine Bedürfnisse optimieren.