So, ich habe es mit timberwolf196.local/visu versucht und war überrascht das gar nichts geladen wird. Da habe ich beim schreiben des Thread wohl etwas falsch beschrieben.
Das Debuggen zeigt auch keine Fehler, ich kann nur die serviceworker.js sehen. Diese habe ich mal ChatGPT geben und gefragt was den Safari 15.X aus den Tritt bringen kann.
Das war ist Antwort.
Kurzfassung: Deine serviceworker.js ist grundsätzlich modern und okay – aber es gibt 3 Stellen, die Safari/WebKit 15 (iPadOS 15.x) in der Praxis gern „aus dem Tritt“ bringen und bewirken können, dass Seiten nicht fertig laden oder scheinbar hängen:
1) fetch-Event: Branch ohne respondWith
In deinem Code:
self.addEventListener('fetch', function(event) {
...
let cache = self.findCacheMatch(event.request);
if (!cache) {
console.info('no cache found');
return fetch(event.request); // <- Problematisch in Safari 15
}
event.respondWith(
caches.open(cacheName).then( ... )
);
});
Wenn du einen fetch-Listener hast, solltest du immer event.respondWith(...) aufrufen – auch beim einfachen Netz-Fallback.
Safari 15 hat (je nach Build) den unschönen Edge Case, dass ein fetch-Listener, der manchmal kein respondWith setzt, zu doppelten oder hängenden Netzwerkzugriffen führen kann.
Fix (sicher für alle Browser, inkl. Safari 15):
self.addEventListener('fetch', function(event) {
const cache = self.findCacheMatch(event.request);
if (!cache) {
event.respondWith(fetch(event.request)); // <-- immer respondWith
return;
}
const cacheName = cache.name;
event.respondWith(
caches.open(cacheName).then(cache => {
return cache.match(event.request).then(response => {
if (response) return response;
return fetch(event.request.clone() /*, {cache: 'no-cache'}*/).then(res => {
if (res && res.status < 400) cache.put(event.request, res.clone());
return res;
});
});
})
);
});
2) cache-Option im fetch-Init
fetch(event.request.clone(), { cache: "no-cache" })
Safari 15 hat bei Request.cache-Modi (v. a. in Service Workern) teils inkonsistentes Verhalten. Meist wird die Option ignoriert (okay), aber es gibt Setups, bei denen das Zusammenspiel mit dem SW-Cache zu unerwarteten Cache-Treffern oder fehlenden Updates führt.
Empfehlung: Für Netz-Fetch im SW ohne Cache-Interferenz einfach ohne die cache-Option arbeiten (oder no-store testen). Am zuverlässigsten ist: Option weglassen.
3) Robustheit von findCacheMatch / URL-Parsing
self.findCacheMatch = function(request) {
var url = new URL(request.url); // kann bei Nicht-HTTP(S) scheitern
...
}
Bei nicht-HTTP(S)-Requests (z. B. data:, blob:, chrome-extension:) kann new URL(...) eine Exception werfen. Das passiert selten – aber wenn, reißt es den Fetch-Handler ab und die Seite lädt nicht fertig.
Fix (defensiv):
self.findCacheMatch = function(request) {
try {
const url = new URL(request.url);
for (const key of Object.keys(CURRENT_CACHES)) {
if (url.pathname.match(CURRENT_CACHES[key].match)) {
return CURRENT_CACHES[key];
}
}
} catch (e) {
// Nicht-HTTP(S) oder ungültige URL -> nicht cachen
}
return null;
};
4) (Optional, aber wichtig für Safari) activate sauber nutzen
Du hast install + skipWaiting(), aber kein activate. Safari 15 bleibt mitunter beim alten SW hängen, bis ein Tab wirklich neu geöffnet wird.
Ergänzen:
self.addEventListener('activate', (event) => {
event.waitUntil(self.clients.claim()); // Kontrolle sofort übernehmen
});
5) Unkritisch, aber nice to have
console.debug(...) ist ok; zur Sicherheit ggf. vorher console.debug = console.debug || console.log;.
Object.values/Set sind in Safari 15 vorhanden – passt.
Deine Regexe enthalten keine Look-behinds (die wären in Safari 15 problematisch); also hier alles gut.
TL;DR – Drop-in Patch
Ersetze in deinem SW:
Fetch-Branch ohne respondWith → immer event.respondWith(fetch(...))
Lass die cache: "no-cache"-Option weg
Mach findCacheMatch try/catch-robust
Füge einen activate-Handler mit clients.claim() hinzu
evtl hilft euch das weiter.
Gruß
Ralf