206 lines
5.2 KiB
JavaScript
206 lines
5.2 KiB
JavaScript
// Service Worker para PWA
|
|
// Cache First Strategy para funcionamiento offline
|
|
|
|
const isDevelopment = self.location.hostname === 'localhost' ||
|
|
self.location.hostname === '127.0.0.1' ||
|
|
self.location.hostname === '[::1]';
|
|
|
|
if (isDevelopment) {
|
|
self.addEventListener('install', (event) => {
|
|
console.log('[SW] Development mode detected, skipping installation');
|
|
self.skipWaiting();
|
|
});
|
|
|
|
self.addEventListener('activate', (event) => {
|
|
console.log('[SW] Development mode detected, unregistering...');
|
|
event.waitUntil(
|
|
self.clients.matchAll().then((clients) => {
|
|
clients.forEach((client) => {
|
|
client.postMessage({ type: 'SW_UNREGISTER' });
|
|
});
|
|
}).then(() => {
|
|
return self.registration.unregister();
|
|
})
|
|
);
|
|
});
|
|
|
|
self.addEventListener('fetch', (event) => {
|
|
return;
|
|
});
|
|
}
|
|
|
|
const CACHE_VERSION = 'v1.0.0';
|
|
const CACHE_NAME = `codigo0-${CACHE_VERSION}`;
|
|
const RUNTIME_CACHE = `codigo0-runtime-${CACHE_VERSION}`;
|
|
|
|
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}`;
|
|
};
|
|
|
|
const STATIC_ASSETS = [
|
|
normalizePath('/'),
|
|
normalizePath('/index.html'),
|
|
normalizePath('/manifest.json'),
|
|
normalizePath('/favicon.ico'),
|
|
];
|
|
|
|
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 Promise.allSettled(
|
|
STATIC_ASSETS.map(url =>
|
|
cache.add(url).catch(err => {
|
|
console.warn(`[SW] Failed to cache ${url}:`, err);
|
|
return null;
|
|
})
|
|
)
|
|
);
|
|
})
|
|
.then(() => {
|
|
console.log('[SW] Static assets cached');
|
|
self.skipWaiting();
|
|
})
|
|
.catch((error) => {
|
|
console.error('[SW] Installation failed:', error);
|
|
self.skipWaiting();
|
|
})
|
|
);
|
|
});
|
|
|
|
self.addEventListener('activate', (event) => {
|
|
console.log('[SW] Activating service worker...');
|
|
|
|
event.waitUntil(
|
|
caches.keys().then((cacheNames) => {
|
|
return Promise.all(
|
|
cacheNames
|
|
.filter((cacheName) => {
|
|
return cacheName !== CACHE_NAME && cacheName !== RUNTIME_CACHE;
|
|
})
|
|
.map((cacheName) => {
|
|
console.log('[SW] Deleting old cache:', cacheName);
|
|
return caches.delete(cacheName);
|
|
})
|
|
);
|
|
})
|
|
.then(() => self.clients.claim())
|
|
);
|
|
});
|
|
|
|
self.addEventListener('fetch', (event) => {
|
|
const { request } = event;
|
|
const url = new URL(request.url);
|
|
|
|
if (request.method !== 'GET') {
|
|
return;
|
|
}
|
|
|
|
if (url.origin !== location.origin) {
|
|
return;
|
|
}
|
|
|
|
if (
|
|
url.hostname === 'localhost' ||
|
|
url.hostname === '127.0.0.1' ||
|
|
url.hostname === '[::1]'
|
|
) {
|
|
if (
|
|
url.pathname.startsWith('/src/') ||
|
|
url.pathname.startsWith('/@') ||
|
|
url.pathname.startsWith('/node_modules/') ||
|
|
url.pathname.includes('?t=') ||
|
|
url.pathname.endsWith('.tsx') ||
|
|
url.pathname.endsWith('.ts') ||
|
|
url.pathname.includes('node_modules') ||
|
|
url.searchParams.has('import') ||
|
|
url.protocol === 'ws:' ||
|
|
url.protocol === 'wss:'
|
|
) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (
|
|
request.destination === 'script' ||
|
|
request.destination === 'style' ||
|
|
request.destination === 'image' ||
|
|
request.destination === 'font' ||
|
|
url.pathname.endsWith('.md') ||
|
|
url.pathname.includes('/assets/')
|
|
) {
|
|
event.respondWith(cacheFirst(request));
|
|
} else {
|
|
event.respondWith(networkFirst(request));
|
|
}
|
|
});
|
|
|
|
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);
|
|
if (request.destination === 'image') {
|
|
return new Response('', { status: 404 });
|
|
}
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
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;
|
|
}
|
|
}
|
|
|
|
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);
|
|
})
|
|
);
|
|
}
|
|
}); |