372 lines
10 KiB
JavaScript
372 lines
10 KiB
JavaScript
/**
|
|
* MYP Platform - CSS Caching Service Worker
|
|
* Intelligentes Caching für optimierte CSS-Performance
|
|
*/
|
|
|
|
const CACHE_NAME = 'myp-css-cache-v1.0';
|
|
const CSS_CACHE_NAME = 'myp-css-resources-v1.0';
|
|
|
|
// Kritische CSS-Ressourcen für sofortiges Caching
|
|
const CRITICAL_CSS_RESOURCES = [
|
|
'/static/css/caching-optimizations.css',
|
|
'/static/css/optimization-animations.css',
|
|
'/static/css/glassmorphism.css',
|
|
'/static/css/professional-theme.css',
|
|
'/static/css/tailwind.min.css'
|
|
];
|
|
|
|
// Nicht-kritische CSS-Ressourcen für Prefetching
|
|
const NON_CRITICAL_CSS_RESOURCES = [
|
|
'/static/css/components.css',
|
|
'/static/css/printers.css',
|
|
'/static/fontawesome/css/all.min.css'
|
|
];
|
|
|
|
// CSS-spezifische Konfiguration
|
|
const CSS_CACHE_CONFIG = {
|
|
maxAge: 24 * 60 * 60 * 1000, // 24 Stunden
|
|
maxEntries: 50,
|
|
networkTimeoutSeconds: 5
|
|
};
|
|
|
|
// Service Worker Installation
|
|
self.addEventListener('install', event => {
|
|
console.log('[CSS-SW] Service Worker wird installiert...');
|
|
|
|
event.waitUntil(
|
|
caches.open(CSS_CACHE_NAME)
|
|
.then(cache => {
|
|
console.log('[CSS-SW] Kritische CSS-Ressourcen werden gecacht...');
|
|
return cache.addAll(CRITICAL_CSS_RESOURCES);
|
|
})
|
|
.then(() => {
|
|
console.log('[CSS-SW] Installation abgeschlossen');
|
|
return self.skipWaiting();
|
|
})
|
|
.catch(error => {
|
|
console.error('[CSS-SW] Fehler bei Installation:', error);
|
|
})
|
|
);
|
|
});
|
|
|
|
// Service Worker Aktivierung
|
|
self.addEventListener('activate', event => {
|
|
console.log('[CSS-SW] Service Worker wird aktiviert...');
|
|
|
|
event.waitUntil(
|
|
caches.keys()
|
|
.then(cacheNames => {
|
|
return Promise.all(
|
|
cacheNames.map(cacheName => {
|
|
// Alte Caches löschen
|
|
if (cacheName !== CACHE_NAME && cacheName !== CSS_CACHE_NAME) {
|
|
console.log('[CSS-SW] Alter Cache wird gelöscht:', cacheName);
|
|
return caches.delete(cacheName);
|
|
}
|
|
})
|
|
);
|
|
})
|
|
.then(() => {
|
|
console.log('[CSS-SW] Aktivierung abgeschlossen');
|
|
return self.clients.claim();
|
|
})
|
|
.then(() => {
|
|
// Nicht-kritische Ressourcen im Hintergrund prefetchen
|
|
return prefetchNonCriticalResources();
|
|
})
|
|
);
|
|
});
|
|
|
|
// CSS-Request-Behandlung mit Cache-First-Strategie
|
|
self.addEventListener('fetch', event => {
|
|
const { request } = event;
|
|
|
|
// Nur CSS-Requests verarbeiten
|
|
if (!request.url.includes('.css') && !request.url.includes('/static/css/')) {
|
|
return;
|
|
}
|
|
|
|
event.respondWith(
|
|
handleCSSRequest(request)
|
|
);
|
|
});
|
|
|
|
// CSS-Request-Handler mit intelligenter Cache-Strategie
|
|
async function handleCSSRequest(request) {
|
|
const url = new URL(request.url);
|
|
|
|
try {
|
|
// 1. Cache-First für CSS-Dateien
|
|
const cachedResponse = await caches.match(request);
|
|
|
|
if (cachedResponse) {
|
|
console.log('[CSS-SW] Cache-Hit für:', url.pathname);
|
|
|
|
// Hintergrund-Update für kritische Ressourcen
|
|
if (CRITICAL_CSS_RESOURCES.some(resource => url.pathname.includes(resource))) {
|
|
updateCacheInBackground(request);
|
|
}
|
|
|
|
return cachedResponse;
|
|
}
|
|
|
|
// 2. Network-Request mit Timeout
|
|
const networkResponse = await fetchWithTimeout(request, CSS_CACHE_CONFIG.networkTimeoutSeconds * 1000);
|
|
|
|
if (networkResponse && networkResponse.ok) {
|
|
// Response für Cache klonen
|
|
const responseToCache = networkResponse.clone();
|
|
|
|
// Asynchron cachen
|
|
cacheResponse(request, responseToCache);
|
|
|
|
console.log('[CSS-SW] Network-Response für:', url.pathname);
|
|
return networkResponse;
|
|
}
|
|
|
|
// 3. Fallback für kritische CSS
|
|
return await getFallbackCSS(request);
|
|
|
|
} catch (error) {
|
|
console.error('[CSS-SW] Fehler bei CSS-Request:', error);
|
|
return await getFallbackCSS(request);
|
|
}
|
|
}
|
|
|
|
// Network-Request mit Timeout
|
|
function fetchWithTimeout(request, timeout) {
|
|
return new Promise((resolve, reject) => {
|
|
const timer = setTimeout(() => {
|
|
reject(new Error('Network timeout'));
|
|
}, timeout);
|
|
|
|
fetch(request)
|
|
.then(response => {
|
|
clearTimeout(timer);
|
|
resolve(response);
|
|
})
|
|
.catch(error => {
|
|
clearTimeout(timer);
|
|
reject(error);
|
|
});
|
|
});
|
|
}
|
|
|
|
// Response asynchron cachen
|
|
async function cacheResponse(request, response) {
|
|
try {
|
|
const cache = await caches.open(CSS_CACHE_NAME);
|
|
await cache.put(request, response);
|
|
|
|
// Cache-Größe prüfen und ggf. alte Einträge löschen
|
|
await maintainCacheSize();
|
|
|
|
} catch (error) {
|
|
console.error('[CSS-SW] Fehler beim Cachen:', error);
|
|
}
|
|
}
|
|
|
|
// Cache-Größe überwachen und bereinigen
|
|
async function maintainCacheSize() {
|
|
try {
|
|
const cache = await caches.open(CSS_CACHE_NAME);
|
|
const requests = await cache.keys();
|
|
|
|
if (requests.length > CSS_CACHE_CONFIG.maxEntries) {
|
|
console.log('[CSS-SW] Cache-Bereinigung wird durchgeführt...');
|
|
|
|
// Älteste Einträge löschen (LRU-ähnlich)
|
|
const excessCount = requests.length - CSS_CACHE_CONFIG.maxEntries;
|
|
for (let i = 0; i < excessCount; i++) {
|
|
await cache.delete(requests[i]);
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.error('[CSS-SW] Fehler bei Cache-Wartung:', error);
|
|
}
|
|
}
|
|
|
|
// Hintergrund-Update für kritische Ressourcen
|
|
async function updateCacheInBackground(request) {
|
|
try {
|
|
const response = await fetch(request);
|
|
if (response && response.ok) {
|
|
const cache = await caches.open(CSS_CACHE_NAME);
|
|
await cache.put(request, response.clone());
|
|
console.log('[CSS-SW] Hintergrund-Update für:', request.url);
|
|
}
|
|
} catch (error) {
|
|
console.log('[CSS-SW] Hintergrund-Update fehlgeschlagen:', error);
|
|
}
|
|
}
|
|
|
|
// Fallback-CSS für kritische Requests
|
|
async function getFallbackCSS(request) {
|
|
const url = new URL(request.url);
|
|
|
|
// Minimales Fallback-CSS für kritische Komponenten
|
|
const fallbackCSS = `
|
|
/* Fallback CSS für Offline-Nutzung */
|
|
body {
|
|
font-family: system-ui, sans-serif;
|
|
margin: 0;
|
|
padding: 20px;
|
|
background: #f8fafc;
|
|
color: #1f2937;
|
|
}
|
|
.offline-notice {
|
|
background: #fef3c7;
|
|
border: 1px solid #f59e0b;
|
|
border-radius: 8px;
|
|
padding: 16px;
|
|
margin-bottom: 20px;
|
|
text-align: center;
|
|
}
|
|
.btn {
|
|
background: #0073ce;
|
|
color: white;
|
|
border: none;
|
|
padding: 8px 16px;
|
|
border-radius: 4px;
|
|
cursor: pointer;
|
|
}
|
|
.card {
|
|
background: white;
|
|
border: 1px solid #e5e7eb;
|
|
border-radius: 8px;
|
|
padding: 16px;
|
|
margin-bottom: 16px;
|
|
}
|
|
`;
|
|
|
|
return new Response(fallbackCSS, {
|
|
headers: {
|
|
'Content-Type': 'text/css',
|
|
'Cache-Control': 'no-cache'
|
|
}
|
|
});
|
|
}
|
|
|
|
// Nicht-kritische Ressourcen im Hintergrund prefetchen
|
|
async function prefetchNonCriticalResources() {
|
|
try {
|
|
const cache = await caches.open(CSS_CACHE_NAME);
|
|
|
|
for (const resource of NON_CRITICAL_CSS_RESOURCES) {
|
|
try {
|
|
const request = new Request(resource);
|
|
const cachedResponse = await cache.match(request);
|
|
|
|
if (!cachedResponse) {
|
|
const response = await fetch(request);
|
|
if (response && response.ok) {
|
|
await cache.put(request, response);
|
|
console.log('[CSS-SW] Prefetch erfolgreich für:', resource);
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.log('[CSS-SW] Prefetch fehlgeschlagen für:', resource);
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.error('[CSS-SW] Fehler beim Prefetching:', error);
|
|
}
|
|
}
|
|
|
|
// Message-Handler für Cache-Management
|
|
self.addEventListener('message', event => {
|
|
const { type, data } = event.data;
|
|
|
|
switch (type) {
|
|
case 'SKIP_WAITING':
|
|
self.skipWaiting();
|
|
break;
|
|
|
|
case 'CLEAR_CSS_CACHE':
|
|
clearCSSCache().then(() => {
|
|
event.ports[0].postMessage({ success: true });
|
|
});
|
|
break;
|
|
|
|
case 'PREFETCH_CSS':
|
|
prefetchSpecificCSS(data.urls).then(() => {
|
|
event.ports[0].postMessage({ success: true });
|
|
});
|
|
break;
|
|
|
|
case 'GET_CACHE_STATS':
|
|
getCacheStats().then(stats => {
|
|
event.ports[0].postMessage(stats);
|
|
});
|
|
break;
|
|
}
|
|
});
|
|
|
|
// CSS-Cache leeren
|
|
async function clearCSSCache() {
|
|
try {
|
|
await caches.delete(CSS_CACHE_NAME);
|
|
console.log('[CSS-SW] CSS-Cache wurde geleert');
|
|
} catch (error) {
|
|
console.error('[CSS-SW] Fehler beim Leeren des CSS-Cache:', error);
|
|
}
|
|
}
|
|
|
|
// Spezifische CSS-Dateien prefetchen
|
|
async function prefetchSpecificCSS(urls) {
|
|
try {
|
|
const cache = await caches.open(CSS_CACHE_NAME);
|
|
|
|
for (const url of urls) {
|
|
try {
|
|
const response = await fetch(url);
|
|
if (response && response.ok) {
|
|
await cache.put(url, response);
|
|
console.log('[CSS-SW] Spezifisches Prefetch für:', url);
|
|
}
|
|
} catch (error) {
|
|
console.log('[CSS-SW] Spezifisches Prefetch fehlgeschlagen für:', url);
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.error('[CSS-SW] Fehler beim spezifischen Prefetching:', error);
|
|
}
|
|
}
|
|
|
|
// Cache-Statistiken abrufen
|
|
async function getCacheStats() {
|
|
try {
|
|
const cache = await caches.open(CSS_CACHE_NAME);
|
|
const requests = await cache.keys();
|
|
|
|
return {
|
|
cssEntries: requests.length,
|
|
maxEntries: CSS_CACHE_CONFIG.maxEntries,
|
|
cacheUtilization: (requests.length / CSS_CACHE_CONFIG.maxEntries) * 100,
|
|
cachedUrls: requests.map(req => req.url)
|
|
};
|
|
} catch (error) {
|
|
console.error('[CSS-SW] Fehler beim Abrufen der Cache-Stats:', error);
|
|
return { error: error.message };
|
|
}
|
|
}
|
|
|
|
// Performance-Monitoring
|
|
self.addEventListener('install', () => {
|
|
console.log('[CSS-SW] Installation gestartet um:', new Date().toISOString());
|
|
});
|
|
|
|
self.addEventListener('activate', () => {
|
|
console.log('[CSS-SW] Aktivierung abgeschlossen um:', new Date().toISOString());
|
|
});
|
|
|
|
// Globaler Error-Handler
|
|
self.addEventListener('error', event => {
|
|
console.error('[CSS-SW] Globaler Fehler:', event.error);
|
|
});
|
|
|
|
self.addEventListener('unhandledrejection', event => {
|
|
console.error('[CSS-SW] Unbehandelte Promise-Rejection:', event.reason);
|
|
});
|
|
|
|
console.log('[CSS-SW] CSS-Caching Service Worker geladen');
|