Files
ftplus-web/app_service_worker.js
2026-07-29 20:16:55 +03:30

127 lines
3.0 KiB
JavaScript

'use strict';
const version = new URL(self.location.href).searchParams.get('v') || 'dev';
const cacheName = `ft-plus-static-${version}`;
const scopeUrl = new URL(self.registration.scope);
const corePaths = [
'./',
'index.html',
'flutter_bootstrap.js',
'flutter.js',
'main.dart.js',
'manifest.json',
'assets/AssetManifest.bin.json',
'assets/FontManifest.json',
];
const coreUrls = corePaths.map((path) => new URL(path, scopeUrl).href);
const staticPrefixes = [
'assets/',
'canvaskit/',
'icons/',
'splashes/',
];
const staticFiles = new Set(['favicon.ico', 'manifest.json']);
const oldFlutterCaches = new Set([
'flutter-app-cache',
'flutter-app-manifest',
'flutter-temp-cache',
]);
self.addEventListener('install', (event) => {
event.waitUntil(
caches
.open(cacheName)
.then((cache) => cache.addAll(coreUrls))
.then(() => self.skipWaiting()),
);
});
self.addEventListener('activate', (event) => {
event.waitUntil(
caches
.keys()
.then((names) =>
Promise.all(
names
.filter(
(name) =>
(name.startsWith('ft-plus-static-') && name !== cacheName) ||
oldFlutterCaches.has(name),
)
.map((name) => caches.delete(name)),
),
)
.then(() => self.clients.claim()),
);
});
self.addEventListener('fetch', (event) => {
const request = event.request;
if (request.method !== 'GET') {
return;
}
const url = new URL(request.url);
if (url.origin !== scopeUrl.origin || !url.pathname.startsWith(scopeUrl.pathname)) {
return;
}
if (request.mode === 'navigate') {
event.respondWith(networkFirst(request, coreUrls[0], false));
return;
}
const relativePath = url.pathname.slice(scopeUrl.pathname.length);
if (isCoreUrl(url.href)) {
event.respondWith(networkFirst(request));
} else if (relativePath.startsWith('workers/')) {
event.respondWith(networkFirst(request));
} else if (
staticPrefixes.some((prefix) => relativePath.startsWith(prefix)) ||
staticFiles.has(relativePath)
) {
event.respondWith(cacheFirst(request));
}
});
function isCoreUrl(url) {
return coreUrls.includes(url);
}
async function networkFirst(request, fallbackUrl, cacheResponse = true) {
const cache = await caches.open(cacheName);
try {
const response = await fetch(request);
if (cacheResponse && response.ok) {
await cache.put(request, response.clone());
}
return response;
} catch (error) {
const cached = await cache.match(request);
if (cached) {
return cached;
}
if (fallbackUrl) {
const fallback = await cache.match(fallbackUrl);
if (fallback) {
return fallback;
}
}
throw error;
}
}
async function cacheFirst(request) {
const cache = await caches.open(cacheName);
const cached = await cache.match(request);
if (cached) {
return cached;
}
const response = await fetch(request);
if (response.ok) {
await cache.put(request, response.clone());
}
return response;
}