Files
NapCatQQ/packages/napcat-webui-backend/src/assets/sw_template.js
手瓜一十雪 a34a86288b Refactor font handling and theme config, switch to CodeMirror editor
Replaces Monaco editor with CodeMirror in the frontend, removing related dependencies and configuration. Refactors font management to support multiple formats (woff, woff2, ttf, otf) and dynamic font switching, including backend API and frontend theme config UI. Adds gzip compression middleware to backend. Updates theme config to allow font selection and custom font upload, and improves theme preview and color customization UI. Cleans up unused code and improves sidebar and terminal font sizing responsiveness.
2025-12-24 18:02:54 +08:00

133 lines
4.4 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
const CACHE_NAME = 'napcat-webui-v{{VERSION}}';
const ASSETS_TO_CACHE = [
'/webui/'
];
// 安装阶段:预缓存核心文件
self.addEventListener('install', (event) => {
self.skipWaiting(); // 强制立即接管
event.waitUntil(
caches.open(CACHE_NAME).then((cache) => {
// 这里的资源如果加载失败不应该阻断 SW 安装
return cache.addAll(ASSETS_TO_CACHE).catch(err => console.warn('Failed to cache core assets', err));
})
);
});
// 激活阶段:清理旧缓存
self.addEventListener('activate', (event) => {
event.waitUntil(
caches.keys().then((cacheNames) => {
return Promise.all(
cacheNames.map((cacheName) => {
if (cacheName.startsWith('napcat-webui-') && cacheName !== CACHE_NAME) {
console.log('[SW] Deleting old cache:', cacheName);
return caches.delete(cacheName);
}
})
);
})
);
self.clients.claim(); // 立即控制所有客户端
});
// 拦截请求
self.addEventListener('fetch', (event) => {
const url = new URL(event.request.url);
// 1. API 请求:仅网络 (Network Only)
if (url.pathname.startsWith('/api/') || url.pathname.includes('/socket')) {
return;
}
// 2. 强缓存策略 (Cache First)
// - 外部 QQ 头像 (q1.qlogo.cn)
// - 静态资源 (assets, fonts)
// - 常见静态文件后缀
const isQLogo = url.hostname === 'q1.qlogo.cn';
const isCustomFont = url.pathname.includes('CustomFont.woff'); // 用户自定义字体,不强缓存
const isThemeCss = url.pathname.includes('files/theme.css'); // 主题 CSS不强缓存
const isStaticAsset = url.pathname.includes('/webui/assets/') ||
url.pathname.includes('/webui/fonts/');
const isStaticFile = /\.(js|css|png|jpg|jpeg|gif|svg|woff|woff2|ttf|eot|ico)$/i.test(url.pathname);
if (!isCustomFont && !isThemeCss && (isQLogo || isStaticAsset || isStaticFile)) {
event.respondWith(
caches.match(event.request).then((response) => {
if (response) {
return response;
}
// 跨域请求 (qlogo) 需要 mode: 'no-cors' 才能缓存 opaque response
// 但 fetch(event.request) 默认会继承 request 的 mode。
// 如果是 img标签发起的请求通常 mode 是 no-cors 或 cors。
// 对于 opaque response (status 0), cache API 允许缓存。
return fetch(event.request).then((response) => {
// 对 qlogo 允许 status 0 (opaque)
// 对其他资源要求 status 200
const isValidResponse = response && (
response.status === 200 ||
response.type === 'basic' ||
(isQLogo && response.type === 'opaque')
);
if (!isValidResponse) {
return response;
}
const responseToCache = response.clone();
caches.open(CACHE_NAME).then((cache) => {
cache.put(event.request, responseToCache);
});
return response;
});
})
);
return;
}
// 3. HTML 页面 / 导航请求 -> 网络优先 (Network First)
if (event.request.mode === 'navigate') {
event.respondWith(
fetch(event.request)
.then((response) => {
const responseToCache = response.clone();
caches.open(CACHE_NAME).then((cache) => {
cache.put(event.request, responseToCache);
});
return response;
})
.catch(() => {
return caches.match(event.request);
})
);
return;
}
// 4. 其他 Same-Origin 请求 -> Stale-While-Revalidate
// 优先返回缓存,同时后台更新缓存,保证下次访问是新的
if (url.origin === self.location.origin) {
event.respondWith(
caches.match(event.request).then((cachedResponse) => {
const fetchPromise = fetch(event.request).then((networkResponse) => {
if (networkResponse && networkResponse.status === 200) {
const responseToCache = networkResponse.clone();
caches.open(CACHE_NAME).then((cache) => {
cache.put(event.request, responseToCache);
});
}
return networkResponse;
});
// 如果有缓存,返回缓存;否则等待网络
return cachedResponse || fetchPromise;
})
);
return;
}
// 默认:网络优先
event.respondWith(
fetch(event.request).catch(() => caches.match(event.request))
);
});