- Оптимизированы мета-теги в index.html и test-pwa.html для лучшей поддержки PWA. - Улучшена структура кода с использованием многострочных атрибутов для мета-тегов. - Обновлен сервисный работник для более эффективного кэширования и обработки запросов. - Добавлены новые функции в pwa.js для управления установкой и обновлением PWA.
236 lines
7.4 KiB
JavaScript
236 lines
7.4 KiB
JavaScript
// Service Worker для NoteJS
|
||
const APP_VERSION = "1.0.5";
|
||
const CACHE_NAME = `notejs-v${APP_VERSION}`;
|
||
const STATIC_CACHE_NAME = `notejs-static-v${APP_VERSION}`;
|
||
|
||
// Файлы для кэширования при установке (только изображения, иконки, логотипы)
|
||
// Манифест убран - не нужен для офлайн работы
|
||
const STATIC_FILES = [
|
||
"/icons/icon-72x72.png",
|
||
"/icons/icon-96x96.png",
|
||
"/icons/icon-128x128.png",
|
||
"/icons/icon-144x144.png",
|
||
"/icons/icon-152x152.png",
|
||
"/icons/icon-192x192.png",
|
||
"/icons/icon-384x384.png",
|
||
"/icons/icon-512x512.png",
|
||
"/icons/icon-32x32.png",
|
||
"/icons/icon-16x16.png",
|
||
"/icons/icon-48x48.png",
|
||
"/icon.svg",
|
||
"/logo.svg",
|
||
];
|
||
|
||
// Установка Service Worker
|
||
self.addEventListener("install", (event) => {
|
||
console.log("[SW] Установка Service Worker");
|
||
|
||
event.waitUntil(
|
||
caches
|
||
.open(STATIC_CACHE_NAME)
|
||
.then((cache) => {
|
||
console.log("[SW] Кэширование статических файлов");
|
||
return cache.addAll(STATIC_FILES);
|
||
})
|
||
.then(() => {
|
||
console.log("[SW] Статические файлы закэшированы");
|
||
return self.skipWaiting();
|
||
})
|
||
.catch((error) => {
|
||
console.error("[SW] Ошибка при кэшировании статических файлов:", error);
|
||
// Продолжаем работу даже если кэширование не удалось
|
||
return self.skipWaiting();
|
||
})
|
||
);
|
||
});
|
||
|
||
// Активация Service Worker
|
||
self.addEventListener("activate", (event) => {
|
||
console.log("[SW] Активация Service Worker");
|
||
|
||
event.waitUntil(
|
||
caches
|
||
.keys()
|
||
.then((cacheNames) => {
|
||
return Promise.all(
|
||
cacheNames.map((cacheName) => {
|
||
// Удаляем старые кэши
|
||
if (cacheName !== STATIC_CACHE_NAME) {
|
||
console.log("[SW] Удаление старого кэша:", cacheName);
|
||
return caches.delete(cacheName);
|
||
}
|
||
})
|
||
);
|
||
})
|
||
.then(() => {
|
||
console.log("[SW] Service Worker активирован");
|
||
return self.clients.claim();
|
||
})
|
||
);
|
||
});
|
||
|
||
// Перехват запросов
|
||
self.addEventListener("fetch", (event) => {
|
||
const { request } = event;
|
||
const url = new URL(request.url);
|
||
|
||
// Пропускаем запросы к API и загрузкам
|
||
if (
|
||
url.pathname.startsWith("/api/") ||
|
||
url.pathname.startsWith("/uploads/") ||
|
||
url.pathname.startsWith("/database/")
|
||
) {
|
||
return;
|
||
}
|
||
|
||
// Пропускаем запросы к внешним ресурсам
|
||
if (url.origin !== location.origin) {
|
||
return;
|
||
}
|
||
|
||
// Пропускаем HTML файлы и CSS - не кэшируем их
|
||
if (
|
||
url.pathname.endsWith(".html") ||
|
||
url.pathname.endsWith(".css") ||
|
||
url.pathname === "/" ||
|
||
url.pathname === "/index.html" ||
|
||
url.pathname === "/login.html" ||
|
||
url.pathname === "/register.html" ||
|
||
url.pathname === "/notes.html" ||
|
||
url.pathname === "/profile.html"
|
||
) {
|
||
return;
|
||
}
|
||
|
||
// Обрабатываем только GET запросы для изображений, иконок и манифеста
|
||
if (request.method === "GET") {
|
||
event.respondWith(handleRequest(request));
|
||
}
|
||
});
|
||
|
||
async function handleRequest(request) {
|
||
try {
|
||
// Сначала пытаемся получить из кэша
|
||
const cachedResponse = await caches.match(request);
|
||
|
||
if (cachedResponse) {
|
||
console.log("[SW] Запрос из кэша:", request.url);
|
||
return cachedResponse;
|
||
}
|
||
|
||
// Если нет в кэше, загружаем из сети
|
||
console.log("[SW] Запрос к сети:", request.url);
|
||
const networkResponse = await fetch(request);
|
||
|
||
// Кэшируем только изображения и иконки (без манифеста)
|
||
if (networkResponse.ok && shouldCache(request)) {
|
||
const cache = await caches.open(STATIC_CACHE_NAME);
|
||
cache.put(request, networkResponse.clone());
|
||
}
|
||
|
||
return networkResponse;
|
||
} catch (error) {
|
||
console.error("[SW] Ошибка при обработке запроса:", error);
|
||
|
||
// НЕ предоставляем fallback - приложение работает только онлайн
|
||
throw error;
|
||
}
|
||
}
|
||
|
||
// Функция для определения, нужно ли кэшировать файл
|
||
function shouldCache(request) {
|
||
const url = new URL(request.url);
|
||
|
||
// Кэшируем только изображения, иконки и логотипы (без манифеста для офлайн работы)
|
||
return (
|
||
url.pathname.includes("/icons/") ||
|
||
url.pathname.endsWith(".png") ||
|
||
url.pathname.endsWith(".jpg") ||
|
||
url.pathname.endsWith(".jpeg") ||
|
||
url.pathname.endsWith(".gif") ||
|
||
url.pathname.endsWith(".webp") ||
|
||
url.pathname.endsWith(".svg")
|
||
);
|
||
}
|
||
|
||
// Обработка сообщений от основного потока
|
||
self.addEventListener("message", (event) => {
|
||
console.log("[SW] Получено сообщение:", event.data);
|
||
|
||
if (event.data && event.data.type === "SKIP_WAITING") {
|
||
self.skipWaiting();
|
||
}
|
||
|
||
if (event.data && event.data.type === "GET_VERSION") {
|
||
event.ports[0].postMessage({ version: CACHE_NAME });
|
||
}
|
||
|
||
if (event.data && event.data.type === "FORCE_UPDATE_CACHE") {
|
||
forceUpdateCache();
|
||
}
|
||
|
||
if (event.data && event.data.type === "CLEAR_ALL_CACHE") {
|
||
clearAllCache();
|
||
}
|
||
});
|
||
|
||
// Функция принудительного обновления кэша
|
||
async function forceUpdateCache() {
|
||
console.log("[SW] Принудительное обновление кэша...");
|
||
|
||
try {
|
||
// Удаляем все старые кэши
|
||
const cacheNames = await caches.keys();
|
||
await Promise.all(
|
||
cacheNames.map((cacheName) => {
|
||
console.log("[SW] Удаление кэша:", cacheName);
|
||
return caches.delete(cacheName);
|
||
})
|
||
);
|
||
|
||
// Создаем новый кэш с актуальной версией
|
||
const newCache = await caches.open(STATIC_CACHE_NAME);
|
||
await newCache.addAll(STATIC_FILES);
|
||
|
||
console.log("[SW] Кэш успешно обновлен до версии:", APP_VERSION);
|
||
|
||
// Уведомляем клиентов об обновлении
|
||
const clients = await self.clients.matchAll();
|
||
clients.forEach((client) => {
|
||
client.postMessage({
|
||
type: "CACHE_UPDATED",
|
||
version: APP_VERSION,
|
||
});
|
||
});
|
||
} catch (error) {
|
||
console.error("[SW] Ошибка при обновлении кэша:", error);
|
||
}
|
||
}
|
||
|
||
// Функция полной очистки кэша
|
||
async function clearAllCache() {
|
||
console.log("[SW] Полная очистка кэша...");
|
||
|
||
try {
|
||
const cacheNames = await caches.keys();
|
||
await Promise.all(
|
||
cacheNames.map((cacheName) => {
|
||
console.log("[SW] Удаление кэша:", cacheName);
|
||
return caches.delete(cacheName);
|
||
})
|
||
);
|
||
|
||
console.log("[SW] Весь кэш очищен");
|
||
|
||
// Уведомляем клиентов об очистке
|
||
const clients = await self.clients.matchAll();
|
||
clients.forEach((client) => {
|
||
client.postMessage({
|
||
type: "CACHE_CLEARED",
|
||
});
|
||
});
|
||
} catch (error) {
|
||
console.error("[SW] Ошибка при очистке кэша:", error);
|
||
}
|
||
}
|