From e801a9b0dc1bf81802021b514d1b77c4c3aec789 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20FAMIBELLE-PRONZOLA?= Date: Thu, 17 Jul 2025 20:09:55 +0400 Subject: [PATCH] add service worker for PWA caching --- sw.js | 222 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 222 insertions(+) create mode 100644 sw.js diff --git a/sw.js b/sw.js new file mode 100644 index 0000000..1cb698f --- /dev/null +++ b/sw.js @@ -0,0 +1,222 @@ +const CACHE_NAME = 'kaubuntu-v1'; +const STATIC_CACHE_NAME = 'kaubuntu-static-v1'; +const DYNAMIC_CACHE_NAME = 'kaubuntu-dynamic-v1'; + +// Ressources à mettre en cache immédiatement +const STATIC_ASSETS = [ + '/', + '/index.php', + '/css/styles.css', + '/css/categories.css', + '/css/search.css', + '/css/video-page.css', + '/css/mastodon-timeline.min.css', + '/js/main.js', + '/js/categories.js', + '/js/search.js', + '/js/mastodon-timeline.umd.js', + '/img/logo.png', + '/img/android-chrome-192x192.png', + '/img/android-chrome-512x512.png', + '/img/apple-touch-icon.png', + '/img/favicon-32x32.png', + '/img/favicon-16x16.png', + '/img/favicon.ico', + '/img/play-icon.svg', + '/site.webmanifest', + 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css', + 'https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js' +]; + +// Pages à mettre en cache +const PAGES_TO_CACHE = [ + '/', + '/index.php', + '/categories.php', + '/recherche.php', + '/mentions-legales.php' +]; + +// Installation du Service Worker +self.addEventListener('install', event => { + console.log('Service Worker: Installation'); + + event.waitUntil( + caches.open(STATIC_CACHE_NAME) + .then(cache => { + console.log('Service Worker: Mise en cache des assets statiques'); + return cache.addAll(STATIC_ASSETS); + }) + .then(() => { + return self.skipWaiting(); + }) + .catch(err => { + console.error('Service Worker: Erreur lors de la mise en cache:', err); + }) + ); +}); + +// Activation du Service Worker +self.addEventListener('activate', event => { + console.log('Service Worker: Activation'); + + event.waitUntil( + caches.keys() + .then(cacheNames => { + return Promise.all( + cacheNames.map(cacheName => { + if (cacheName !== STATIC_CACHE_NAME && cacheName !== DYNAMIC_CACHE_NAME) { + console.log('Service Worker: Suppression du cache obsolète:', cacheName); + return caches.delete(cacheName); + } + }) + ); + }) + .then(() => { + return self.clients.claim(); + }) + ); +}); + +// Interception des requêtes +self.addEventListener('fetch', event => { + const { request } = event; + const url = new URL(request.url); + + // Ignorer les requêtes non-GET + if (request.method !== 'GET') { + return; + } + + // Ignorer les requêtes vers des domaines externes (sauf CDN) + if (url.origin !== location.origin && + !url.hostname.includes('cdnjs.cloudflare.com')) { + return; + } + + // Stratégie Cache First pour les assets statiques + if (isStaticAsset(request.url)) { + event.respondWith( + caches.match(request) + .then(response => { + if (response) { + return response; + } + return fetch(request) + .then(response => { + if (response.status === 200) { + const responseClone = response.clone(); + caches.open(STATIC_CACHE_NAME) + .then(cache => cache.put(request, responseClone)); + } + return response; + }); + }) + .catch(() => { + // Fallback pour les images + if (request.destination === 'image') { + return caches.match('/img/logo.png'); + } + }) + ); + return; + } + + // Stratégie Network First pour les pages dynamiques + if (isPageRequest(request.url)) { + event.respondWith( + fetch(request) + .then(response => { + if (response.status === 200) { + const responseClone = response.clone(); + caches.open(DYNAMIC_CACHE_NAME) + .then(cache => cache.put(request, responseClone)); + } + return response; + }) + .catch(() => { + return caches.match(request) + .then(response => { + if (response) { + return response; + } + // Fallback vers la page d'accueil + return caches.match('/') || caches.match('/index.php'); + }); + }) + ); + return; + } + + // Stratégie Network First pour les API et AJAX + if (isApiRequest(request.url)) { + event.respondWith( + fetch(request) + .catch(() => { + return new Response( + JSON.stringify({ + error: 'Pas de connexion internet', + offline: true + }), + { + status: 503, + headers: { + 'Content-Type': 'application/json' + } + } + ); + }) + ); + return; + } +}); + +// Fonctions utilitaires +function isStaticAsset(url) { + return url.includes('/css/') || + url.includes('/js/') || + url.includes('/img/') || + url.includes('cdnjs.cloudflare.com') || + url.endsWith('.css') || + url.endsWith('.js') || + url.endsWith('.png') || + url.endsWith('.jpg') || + url.endsWith('.jpeg') || + url.endsWith('.svg') || + url.endsWith('.ico') || + url.endsWith('.webmanifest'); +} + +function isPageRequest(url) { + return url.endsWith('/') || + url.endsWith('.php') || + url.includes('index.php') || + url.includes('categories.php') || + url.includes('recherche.php') || + url.includes('video.php') || + url.includes('mentions-legales.php'); +} + +function isApiRequest(url) { + return url.includes('/ajax/') || + url.includes('api') || + url.includes('mastodon-config.php'); +} + +// Gestion des messages du client +self.addEventListener('message', event => { + if (event.data && event.data.type === 'SKIP_WAITING') { + self.skipWaiting(); + } +}); + +// Notification de mise à jour +self.addEventListener('message', event => { + if (event.data && event.data.type === 'CHECK_UPDATE') { + // Vérifier s'il y a une mise à jour + event.ports[0].postMessage({ + type: 'UPDATE_AVAILABLE', + version: CACHE_NAME + }); + } +}); \ No newline at end of file