// Service Worker for performance optimization const CACHE_NAME = 'n8n-demo-v1'; const STATIC_CACHE = 'static-v1'; const DYNAMIC_CACHE = 'dynamic-v1'; // 需要缓存的静态资源 const STATIC_FILES = [ '/', '/index.html', '/pages/overview.html', '/pages/exhibition.html', '/pages/marketing.html', '/pages/operation.html', '/pages/budget.html', '/pages/risk.html', '/js/nav-component.js', '/js/back-to-top.js', '/js/mobile-optimize.js', '/js/performance-optimizer.js', '/js/page-loader.js', '/css/styles.css', '/css/animations.css' ]; // 缓存策略配置 const CACHE_STRATEGIES = { // 静态资源:缓存优先 static: { pattern: /\.(js|css|woff|woff2|ttf|eot)$/, strategy: 'cacheFirst', maxAge: 30 * 24 * 60 * 60 * 1000 // 30天 }, // HTML页面:网络优先,失败时使用缓存 html: { pattern: /\.html$/, strategy: 'networkFirst', maxAge: 24 * 60 * 60 * 1000 // 1天 }, // 图片:缓存优先 images: { pattern: /\.(png|jpg|jpeg|gif|svg|webp)$/, strategy: 'cacheFirst', maxAge: 7 * 24 * 60 * 60 * 1000 // 7天 }, // 外部资源:网络优先 external: { pattern: /^https:\/\/(fonts\.googleapis\.com|cdnjs\.cloudflare\.com|cdn\.jsdelivr\.net)/, strategy: 'networkFirst', maxAge: 7 * 24 * 60 * 60 * 1000 // 7天 } }; // 安装事件 - 缓存静态资源 self.addEventListener('install', event => { console.log('SW: Install event'); event.waitUntil( caches.open(STATIC_CACHE) .then(cache => { console.log('SW: Caching static files'); return cache.addAll(STATIC_FILES); }) .then(() => { console.log('SW: Static files cached'); return self.skipWaiting(); }) .catch(err => { console.error('SW: Failed to cache static files', err); }) ); }); // 激活事件 - 清理旧缓存 self.addEventListener('activate', event => { console.log('SW: Activate event'); event.waitUntil( caches.keys() .then(cacheNames => { return Promise.all( cacheNames.map(cacheName => { // 删除旧版本的缓存 if (cacheName !== STATIC_CACHE && cacheName !== DYNAMIC_CACHE) { console.log('SW: Deleting old cache:', cacheName); return caches.delete(cacheName); } }) ); }) .then(() => { console.log('SW: Old caches cleaned'); return self.clients.claim(); }) ); }); // 获取事件 - 实现缓存策略 self.addEventListener('fetch', event => { // 只处理 GET 请求 if (event.request.method !== 'GET') { return; } const url = new URL(event.request.url); // 跳过 chrome-extension 等协议 if (!url.protocol.startsWith('http')) { return; } event.respondWith(handleFetch(event.request)); }); // 处理请求的核心函数 async function handleFetch(request) { const url = new URL(request.url); try { // 确定缓存策略 const strategy = getCacheStrategy(request); switch (strategy.strategy) { case 'cacheFirst': return await cacheFirst(request, strategy); case 'networkFirst': return await networkFirst(request, strategy); case 'networkOnly': return await fetch(request); default: return await networkFirst(request, strategy); } } catch (error) { console.error('SW: Fetch failed:', error); // 返回离线页面或缓存的响应 return await getOfflineResponse(request); } } // 获取缓存策略 function getCacheStrategy(request) { const url = request.url; for (const [key, config] of Object.entries(CACHE_STRATEGIES)) { if (config.pattern.test(url)) { return config; } } // 默认策略 return { strategy: 'networkFirst', maxAge: 24 * 60 * 60 * 1000 }; } // 缓存优先策略 async function cacheFirst(request, strategy) { const cacheName = isStaticResource(request) ? STATIC_CACHE : DYNAMIC_CACHE; const cache = await caches.open(cacheName); const cachedResponse = await cache.match(request); if (cachedResponse) { // 检查缓存是否过期 const cachedDate = new Date(cachedResponse.headers.get('date') || Date.now()); const now = new Date(); if (now - cachedDate < strategy.maxAge) { return cachedResponse; } } try { const networkResponse = await fetch(request); if (networkResponse.ok) { // 缓存新响应 await cache.put(request, networkResponse.clone()); } return networkResponse; } catch (error) { // 网络失败,返回缓存(即使过期) if (cachedResponse) { return cachedResponse; } throw error; } } // 网络优先策略 async function networkFirst(request, strategy) { const cacheName = isStaticResource(request) ? STATIC_CACHE : DYNAMIC_CACHE; const cache = await caches.open(cacheName); try { const networkResponse = await fetch(request); if (networkResponse.ok) { // 缓存响应 await cache.put(request, networkResponse.clone()); } return networkResponse; } catch (error) { // 网络失败,尝试从缓存获取 const cachedResponse = await cache.match(request); if (cachedResponse) { return cachedResponse; } throw error; } } // 判断是否为静态资源 function isStaticResource(request) { const url = new URL(request.url); return STATIC_FILES.some(file => url.pathname.endsWith(file)); } // 获取离线响应 async function getOfflineResponse(request) { const url = new URL(request.url); // 如果是 HTML 请求,返回主页 if (request.headers.get('accept')?.includes('text/html')) { const cache = await caches.open(STATIC_CACHE); return await cache.match('/index.html') || new Response('Offline', { status: 503 }); } // 其他资源返回 503 return new Response('Offline', { status: 503 }); } // 监听消息事件 self.addEventListener('message', event => { 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 }); } }); // 后台同步(如果支持) self.addEventListener('sync', event => { if (event.tag === 'background-sync') { event.waitUntil(doBackgroundSync()); } }); async function doBackgroundSync() { // 这里可以执行后台同步任务 console.log('SW: Background sync'); } // 推送通知(如果需要) self.addEventListener('push', event => { if (event.data) { const data = event.data.json(); const options = { body: data.body, icon: data.icon || '/favicon.ico', badge: '/badge.png', vibrate: [200, 100, 200], data: data.data, actions: data.actions }; event.waitUntil( self.registration.showNotification(data.title, options) ); } }); // 通知点击事件 self.addEventListener('notificationclick', event => { event.notification.close(); event.waitUntil( clients.openWindow(event.notification.data?.url || '/') ); });