feat: tính năng offline cho upload ảnh và tải bản đồ
This commit is contained in:
@@ -0,0 +1,116 @@
|
||||
/**
|
||||
* sw.js — YoTrip Service Worker
|
||||
* ─────────────────────────────────────────────────────────────────────────────
|
||||
* Strategy: Network-First with Cache-API fallback.
|
||||
*
|
||||
* Caches:
|
||||
* 1. App Shell (static assets): cached at install time
|
||||
* 2. OpenStreetMap tiles: cached dynamically on first fetch, served from
|
||||
* cache when offline — so previously visited map areas remain navigable
|
||||
*
|
||||
* Cache names are versioned so old caches get evicted on SW update.
|
||||
*/
|
||||
|
||||
const SHELL_CACHE = 'yotrip-shell-v1';
|
||||
const MAP_CACHE = 'yotrip-map-tiles-v1';
|
||||
|
||||
// App shell files to pre-cache at install
|
||||
const SHELL_URLS = [
|
||||
'/',
|
||||
'/index.html',
|
||||
'/manifest.json',
|
||||
'/favicon.ico',
|
||||
];
|
||||
|
||||
// URL patterns for map tile providers
|
||||
const MAP_TILE_ORIGINS = [
|
||||
'tile.openstreetmap.org',
|
||||
'a.tile.openstreetmap.org',
|
||||
'b.tile.openstreetmap.org',
|
||||
'c.tile.openstreetmap.org',
|
||||
'tiles.stadiamaps.com',
|
||||
'server.arcgisonline.com',
|
||||
];
|
||||
|
||||
// ─── Install ──────────────────────────────────────────────────────────────
|
||||
|
||||
self.addEventListener('install', (event) => {
|
||||
console.log('[SW] Installing yotrip service worker…');
|
||||
event.waitUntil(
|
||||
caches.open(SHELL_CACHE).then((cache) => {
|
||||
return cache.addAll(SHELL_URLS).catch((err) => {
|
||||
// Non-fatal: some shell files may not exist in dev mode
|
||||
console.warn('[SW] Shell pre-cache partial failure (non-fatal):', err);
|
||||
});
|
||||
})
|
||||
);
|
||||
// Activate immediately without waiting for old tabs to close
|
||||
self.skipWaiting();
|
||||
});
|
||||
|
||||
// ─── Activate ─────────────────────────────────────────────────────────────
|
||||
|
||||
self.addEventListener('activate', (event) => {
|
||||
const CURRENT_CACHES = [SHELL_CACHE, MAP_CACHE];
|
||||
event.waitUntil(
|
||||
caches.keys().then((cacheNames) =>
|
||||
Promise.all(
|
||||
cacheNames
|
||||
.filter((name) => !CURRENT_CACHES.includes(name))
|
||||
.map((name) => {
|
||||
console.log('[SW] Evicting stale cache:', name);
|
||||
return caches.delete(name);
|
||||
})
|
||||
)
|
||||
)
|
||||
);
|
||||
// Take control of all open clients immediately
|
||||
self.clients.claim();
|
||||
});
|
||||
|
||||
// ─── Fetch ────────────────────────────────────────────────────────────────
|
||||
|
||||
self.addEventListener('fetch', (event) => {
|
||||
const url = new URL(event.request.url);
|
||||
|
||||
// 1. Map tile requests — Network-First, fall back to cache
|
||||
const isMapTile = MAP_TILE_ORIGINS.some((origin) => url.hostname.includes(origin));
|
||||
if (isMapTile) {
|
||||
event.respondWith(
|
||||
fetch(event.request)
|
||||
.then((response) => {
|
||||
if (response && response.status === 200) {
|
||||
const clone = response.clone();
|
||||
caches.open(MAP_CACHE).then((cache) => {
|
||||
cache.put(event.request, clone);
|
||||
});
|
||||
}
|
||||
return response;
|
||||
})
|
||||
.catch(() => caches.match(event.request))
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. API calls — Network-Only (never cache API responses)
|
||||
if (url.pathname.startsWith('/api/')) {
|
||||
return; // Let the browser handle normally
|
||||
}
|
||||
|
||||
// 3. App shell navigation — Cache-First for HTML, then network
|
||||
if (event.request.mode === 'navigate') {
|
||||
event.respondWith(
|
||||
caches.match('/index.html').then((cached) => {
|
||||
return cached || fetch(event.request);
|
||||
})
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// 4. Static assets (JS/CSS/images) — Cache-First
|
||||
event.respondWith(
|
||||
caches.match(event.request).then((cached) => {
|
||||
return cached || fetch(event.request);
|
||||
})
|
||||
);
|
||||
});
|
||||
Reference in New Issue
Block a user