From 3d9a4832f91029f63471951bfe268702acbf476d Mon Sep 17 00:00:00 2001 From: marc Date: Mon, 24 Aug 2026 23:54:25 +0200 Subject: [PATCH] fix(pwa): geaenderte Kopfzeilen erreichen den Browser wieder MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ein Eintrag im Cache ist eine ganze Antwort, mitsamt ihren Kopfzeilen. Weil index.html vorab im Cache lag und von dort auch „/" beantwortete, bekam der Browser dauerhaft die CSP von damals: eine Aenderung an HONEYBAR_ORIGIN kam nie an, denn der Inhalt der Datei aendert sich dabei nicht, und der Vorab-Cache holt nur Geaendertes nach. Sichtbar als Widerspruch, an dem nichts falsch aussah — das Skript laedt den neuen Ursprung, die CSP erlaubt den alten. Navigationen laufen jetzt Netz zuerst, Cache als Rueckfall; index.html bleibt vorab abgelegt, aber nur noch als letzte Reihe (precacheFallback). Dass sie nicht mehr als Verzeichnisseite fuer „/" einspringt, ist der eigentliche Punkt: sonst kaeme die neue Regel nie zum Zug. Nachgemessen: Wechsel des Ursprungs kommt beim zweiten Aufruf an, und offline laden „/", „/admin" und „/s/" weiterhin die Anwendung. Co-Authored-By: Claude Opus 5 --- frontend/vite.config.ts | 56 +++++++++++++++++++++++++++++++++++------ 1 file changed, 48 insertions(+), 8 deletions(-) diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts index 9baceb7..1895c29 100644 --- a/frontend/vite.config.ts +++ b/frontend/vite.config.ts @@ -40,14 +40,54 @@ export default defineConfig({ VitePWA({ registerType: 'autoUpdate', workbox: { - // Der Service Worker beantwortet jede Navigation aus dem Cache mit - // index.html – nötig, damit Adressen wie /admin oder /s/ auch - // offline funktionieren. Ohne diese Ausnahmen erwischt er aber auch - // Downloads: Ein Klick auf „Download" öffnet eine Navigation zu - // /api/v1/files//download, der Worker liefert die Anwendung statt - // der Datei, und es passiert sichtbar nichts. - navigateFallback: 'index.html', - navigateFallbackDenylist: [/^\/api\//, /^\/dav\//, /^\/share\//, /^\/branding\//, /^\/wopi\//], + // Der Service Worker beantwortet Navigationen — also den Aufruf der + // Seite selbst — **Netz zuerst, Cache als Rueckfall**. + // + // Frueher lag index.html im Vorab-Cache und wurde von dort geliefert. + // Das war schnell, hatte aber eine unscheinbare Folge: Ein Eintrag im + // Cache ist eine ganze Antwort, **mitsamt ihren Kopfzeilen**. Der + // Browser bekam also dauerhaft die CSP von damals. Eine Aenderung an + // HONEYBAR_ORIGIN erreichte ihn nie — der Inhalt der Datei aendert sich + // ja nicht, und der Vorab-Cache holt nur nach, was sich geaendert hat. + // Sichtbar wurde das als Widerspruch, an dem nichts falsch aussah: Das + // Skript laedt den neuen Ursprung, die CSP erlaubt den alten. + // + // precacheFallback haelt dabei, was navigateFallback vorher leistete: + // Ist weder Netz noch Cache da, antwortet die vorab abgelegte + // index.html — Adressen wie /admin oder /s/ funktionieren also + // weiterhin offline. + // + // Ausgenommen sind Downloads und WebDAV: Ein Klick auf „Download" + // oeffnet eine Navigation zu /api/v1/files//download. Faengt der + // Worker die ab, liefert er die Anwendung statt der Datei — und es + // passiert sichtbar nichts. Sie sollen am Worker vorbeigehen, nicht + // von ihm beantwortet werden. + // Der Vorab-Cache beantwortet sonst auch den Aufruf von „/" — er + // rechnet index.html als Verzeichnisseite an. Genau daran scheiterte + // der erste Anlauf: Die Regel unten kam nie zum Zug, weil die Seite + // schon vorher aus dem Vorab-Cache beantwortet wurde, mitsamt alter + // CSP. Als reiner Rueckfall (precacheFallback) bleibt index.html dort + // liegen, nur eben nicht mehr als Antwort auf jede Navigation. + directoryIndex: null, + // vite-plugin-pwa setzt sonst von sich aus navigateFallback: 'index.html' + // — also genau die Vorab-Cache-Antwort, die wir hier los sein wollen. + // Die Sperrliste nimmt jede Adresse davon aus; zustaendig ist dann die + // Regel darunter. + navigateFallbackDenylist: [/./], + runtimeCaching: [ + { + urlPattern: ({ request, url }) => + request.mode === 'navigate' && + !/^\/(api|dav|share|branding|wopi)\//.test(url.pathname), + handler: 'NetworkFirst', + options: { + cacheName: 'aether-seiten', + // Ohne Grenze haengt der Start am langsamsten Netz. + networkTimeoutSeconds: 3, + precacheFallback: { fallbackURL: 'index.html' }, + }, + }, + ], // PDF.js bleibt aussen vor: Betrachter (435 KB), Arbeiter (1,3 MB) // und Standardschriften (800 KB) sind zusammen zweieinhalb Megabyte, // die nur braucht, wer ein PDF oeffnet. Vorab in den Cache zu legen