Fix: SW Network-First für Navigation + versionierte CSS/JS-URLs (v=32)
- sw.js: index.html nie aus Cache (navigation → network-first) - index.html: ?v=32 an layout.css, components.css, api/ui/app.js - sw.js STATIC_ASSETS: versionierte URLs gecacht - app.js: Sidebar-Background per getComputedStyle statt CSS-Variable-String - SW by-v31 → by-v32
This commit is contained in:
parent
b6fae96334
commit
619ff559e6
3 changed files with 33 additions and 24 deletions
|
|
@ -20,10 +20,10 @@
|
||||||
|
|
||||||
<title>Ban Yaro</title>
|
<title>Ban Yaro</title>
|
||||||
|
|
||||||
<!-- CSS: Reihenfolge ist wichtig -->
|
<!-- CSS: Reihenfolge ist wichtig — ?v= zwingt Browser zur Neuladung -->
|
||||||
<link rel="stylesheet" href="/css/design-system.css">
|
<link rel="stylesheet" href="/css/design-system.css">
|
||||||
<link rel="stylesheet" href="/css/layout.css">
|
<link rel="stylesheet" href="/css/layout.css?v=32">
|
||||||
<link rel="stylesheet" href="/css/components.css">
|
<link rel="stylesheet" href="/css/components.css?v=32">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
|
|
@ -215,9 +215,9 @@
|
||||||
<div id="modal-container"></div>
|
<div id="modal-container"></div>
|
||||||
|
|
||||||
<!-- JS: Reihenfolge ist wichtig — erst Basis, dann Features -->
|
<!-- JS: Reihenfolge ist wichtig — erst Basis, dann Features -->
|
||||||
<script src="/js/api.js"></script>
|
<script src="/js/api.js?v=32"></script>
|
||||||
<script src="/js/ui.js"></script>
|
<script src="/js/ui.js?v=32"></script>
|
||||||
<script src="/js/app.js"></script>
|
<script src="/js/app.js?v=32"></script>
|
||||||
|
|
||||||
<!-- Feature-Seiten werden lazy geladen -->
|
<!-- Feature-Seiten werden lazy geladen -->
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -196,17 +196,20 @@ const App = (() => {
|
||||||
const sidebar = document.getElementById('sidebar');
|
const sidebar = document.getElementById('sidebar');
|
||||||
if (!sidebar) return;
|
if (!sidebar) return;
|
||||||
// Inline-Styles: unabhängig vom CSS-Cache-Stand
|
// Inline-Styles: unabhängig vom CSS-Cache-Stand
|
||||||
|
// Inline-Styles: unabhängig vom CSS-Cache; Farben als Fallback hardcoded
|
||||||
|
const bg = getComputedStyle(document.documentElement)
|
||||||
|
.getPropertyValue('--c-surface').trim() || '#ffffff';
|
||||||
sidebar.style.cssText = [
|
sidebar.style.cssText = [
|
||||||
'display:flex',
|
'display:flex',
|
||||||
'position:fixed',
|
'position:fixed',
|
||||||
'top:0', 'left:0', 'bottom:0',
|
'top:0', 'left:0', 'bottom:0',
|
||||||
'width:240px',
|
'width:240px',
|
||||||
'z-index:2000',
|
'z-index:2000',
|
||||||
'background:var(--c-surface,#fff)',
|
`background:${bg}`,
|
||||||
'flex-direction:column',
|
'flex-direction:column',
|
||||||
'overflow:hidden',
|
'overflow:hidden',
|
||||||
'box-shadow:4px 0 24px rgba(0,0,0,0.22)',
|
'box-shadow:4px 0 24px rgba(0,0,0,0.22)',
|
||||||
'border-right:1px solid var(--c-border-light,#eee)',
|
'border-right:1px solid #e5e7eb',
|
||||||
].join(';');
|
].join(';');
|
||||||
document.getElementById('sidebar-backdrop')?.classList.add('visible');
|
document.getElementById('sidebar-backdrop')?.classList.add('visible');
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,18 +3,17 @@
|
||||||
Offline-Cache + Push Notifications
|
Offline-Cache + Push Notifications
|
||||||
============================================================ */
|
============================================================ */
|
||||||
|
|
||||||
const CACHE_VERSION = 'by-v31';
|
const CACHE_VERSION = 'by-v32';
|
||||||
const CACHE_STATIC = `${CACHE_VERSION}-static`;
|
const CACHE_STATIC = `${CACHE_VERSION}-static`;
|
||||||
|
|
||||||
// Diese Dateien werden beim Install gecacht (App Shell)
|
// index.html wird NICHT pre-gecacht (immer Network-First)
|
||||||
const STATIC_ASSETS = [
|
const STATIC_ASSETS = [
|
||||||
'/',
|
|
||||||
'/css/design-system.css',
|
'/css/design-system.css',
|
||||||
'/css/layout.css',
|
'/css/layout.css?v=32',
|
||||||
'/css/components.css',
|
'/css/components.css?v=32',
|
||||||
'/js/api.js',
|
'/js/api.js?v=32',
|
||||||
'/js/ui.js',
|
'/js/ui.js?v=32',
|
||||||
'/js/app.js',
|
'/js/app.js?v=32',
|
||||||
'/manifest.json',
|
'/manifest.json',
|
||||||
'/icons/icon-192.png',
|
'/icons/icon-192.png',
|
||||||
];
|
];
|
||||||
|
|
@ -40,14 +39,11 @@ self.addEventListener('activate', event => {
|
||||||
keys.filter(k => k !== CACHE_STATIC).map(k => caches.delete(k))
|
keys.filter(k => k !== CACHE_STATIC).map(k => caches.delete(k))
|
||||||
))
|
))
|
||||||
.then(() => self.clients.claim())
|
.then(() => self.clients.claim())
|
||||||
// Alle offenen Fenster neu laden, damit neues CSS/JS aktiv wird
|
|
||||||
.then(() => self.clients.matchAll({ type: 'window' }))
|
|
||||||
.then(clients => clients.forEach(c => c.navigate(c.url)))
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
||||||
// FETCH — Cache-First für statische Assets, Network-First für API
|
// FETCH — Network-First für HTML, Cache-First für Assets, Network für API
|
||||||
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
||||||
self.addEventListener('fetch', event => {
|
self.addEventListener('fetch', event => {
|
||||||
const url = new URL(event.request.url);
|
const url = new URL(event.request.url);
|
||||||
|
|
@ -63,12 +59,25 @@ self.addEventListener('fetch', event => {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Navigation (index.html): immer Network-First
|
||||||
|
if (event.request.mode === 'navigate') {
|
||||||
|
event.respondWith(
|
||||||
|
fetch(event.request)
|
||||||
|
.then(response => {
|
||||||
|
const clone = response.clone();
|
||||||
|
caches.open(CACHE_STATIC).then(c => c.put(event.request, clone));
|
||||||
|
return response;
|
||||||
|
})
|
||||||
|
.catch(() => caches.match('/'))
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Statische Assets: Cache-First
|
// Statische Assets: Cache-First
|
||||||
event.respondWith(
|
event.respondWith(
|
||||||
caches.match(event.request)
|
caches.match(event.request)
|
||||||
.then(cached => cached || fetch(event.request)
|
.then(cached => cached || fetch(event.request)
|
||||||
.then(response => {
|
.then(response => {
|
||||||
// Erfolgreiche Responses für statische Assets cachen
|
|
||||||
if (response.ok && event.request.method === 'GET') {
|
if (response.ok && event.request.method === 'GET') {
|
||||||
const clone = response.clone();
|
const clone = response.clone();
|
||||||
caches.open(CACHE_STATIC).then(c => c.put(event.request, clone));
|
caches.open(CACHE_STATIC).then(c => c.put(event.request, clone));
|
||||||
|
|
@ -77,7 +86,6 @@ self.addEventListener('fetch', event => {
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
// Offline-Fallback: App Shell zurückgeben
|
|
||||||
if (event.request.mode === 'navigate') {
|
if (event.request.mode === 'navigate') {
|
||||||
return caches.match('/');
|
return caches.match('/');
|
||||||
}
|
}
|
||||||
|
|
@ -139,7 +147,6 @@ self.addEventListener('notificationclick', event => {
|
||||||
event.waitUntil(
|
event.waitUntil(
|
||||||
clients.matchAll({ type: 'window', includeUncontrolled: true })
|
clients.matchAll({ type: 'window', includeUncontrolled: true })
|
||||||
.then(windowClients => {
|
.then(windowClients => {
|
||||||
// Offenes Fenster fokussieren
|
|
||||||
for (const client of windowClients) {
|
for (const client of windowClients) {
|
||||||
if (client.url.includes(self.location.origin)) {
|
if (client.url.includes(self.location.origin)) {
|
||||||
client.focus();
|
client.focus();
|
||||||
|
|
@ -147,7 +154,6 @@ self.addEventListener('notificationclick', event => {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Neues Fenster öffnen
|
|
||||||
return clients.openWindow(url);
|
return clients.openWindow(url);
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue