codigo0/public/sw.js
planetazuzu b9413d4d0d feat: Corregir rutas PWA para GitHub Pages y añadir listado de medios faltantes
- Añadido plugin de Vite para generar manifest.json dinámicamente con base path correcto
- Actualizado service worker para detectar base path dinámicamente
- Actualizado registro de service worker en main.tsx para usar base path
- Corregido manifest.json para funcionar en GitHub Pages (/guia-tes-digital/)
- Añadido listado completo de medios faltantes con descripciones
- Actualizado documentación de GitHub Pages
- Corregido símbolo > en ViaAerea.tsx
2025-12-17 16:19:37 +01:00

157 lines
4.1 KiB
JavaScript

// Service Worker para PWA
// Cache First Strategy para funcionamiento offline
const CACHE_NAME = 'emerges-tes-v1';
const RUNTIME_CACHE = 'emerges-tes-runtime-v1';
// Detectar base path dinámicamente (para GitHub Pages)
const BASE_PATH = self.location.pathname.split('/').slice(0, -1).join('/') || '/';
const normalizePath = (path) => {
if (path.startsWith('/')) {
return BASE_PATH === '/' ? path : `${BASE_PATH}${path}`;
}
return `${BASE_PATH}/${path}`;
};
// Archivos estáticos a cachear en la instalación
const STATIC_ASSETS = [
normalizePath('/'),
normalizePath('/index.html'),
normalizePath('/manifest.json'),
normalizePath('/favicon.ico'),
];
// Instalación del Service Worker
self.addEventListener('install', (event) => {
console.log('[SW] Installing service worker...');
event.waitUntil(
caches.open(CACHE_NAME)
.then((cache) => {
console.log('[SW] Caching static assets');
return cache.addAll(STATIC_ASSETS);
})
.then(() => self.skipWaiting()) // Activar inmediatamente
);
});
// Activación del Service Worker
self.addEventListener('activate', (event) => {
console.log('[SW] Activating service worker...');
event.waitUntil(
caches.keys().then((cacheNames) => {
return Promise.all(
cacheNames
.filter((cacheName) => {
// Eliminar caches antiguos
return cacheName !== CACHE_NAME && cacheName !== RUNTIME_CACHE;
})
.map((cacheName) => {
console.log('[SW] Deleting old cache:', cacheName);
return caches.delete(cacheName);
})
);
})
.then(() => self.clients.claim()) // Tomar control de todas las páginas
);
});
// Interceptar peticiones
self.addEventListener('fetch', (event) => {
const { request } = event;
const url = new URL(request.url);
// Ignorar peticiones no GET
if (request.method !== 'GET') {
return;
}
// Ignorar peticiones a APIs externas (si las hay)
if (url.origin !== location.origin) {
return;
}
// Estrategia: Cache First para assets estáticos
if (
request.destination === 'script' ||
request.destination === 'style' ||
request.destination === 'image' ||
request.destination === 'font' ||
url.pathname.endsWith('.md')
) {
event.respondWith(cacheFirst(request));
} else {
// Network First para HTML y otros
event.respondWith(networkFirst(request));
}
});
// Cache First Strategy
async function cacheFirst(request) {
const cache = await caches.open(CACHE_NAME);
const cached = await cache.match(request);
if (cached) {
return cached;
}
try {
const response = await fetch(request);
if (response.ok) {
cache.put(request, response.clone());
}
return response;
} catch (error) {
console.error('[SW] Fetch failed:', error);
// Si es una imagen, retornar una imagen placeholder
if (request.destination === 'image') {
return new Response('', { status: 404 });
}
throw error;
}
}
// Network First Strategy
async function networkFirst(request) {
const cache = await caches.open(RUNTIME_CACHE);
try {
const response = await fetch(request);
if (response.ok) {
cache.put(request, response.clone());
}
return response;
} catch (error) {
console.log('[SW] Network failed, trying cache:', error);
const cached = await cache.match(request);
if (cached) {
return cached;
}
// Si no hay cache y estamos offline, retornar index.html para SPA
if (request.mode === 'navigate') {
const indexCache = await caches.open(CACHE_NAME);
const indexHtml = await indexCache.match(normalizePath('/index.html'));
if (indexHtml) {
return indexHtml;
}
}
throw error;
}
}
// Manejar mensajes del cliente
self.addEventListener('message', (event) => {
if (event.data && event.data.type === 'SKIP_WAITING') {
self.skipWaiting();
}
if (event.data && event.data.type === 'CACHE_URLS') {
event.waitUntil(
caches.open(CACHE_NAME).then((cache) => {
return cache.addAll(event.data.urls);
})
);
}
});