Merge branch 'dev'
This commit is contained in:
commit
798a5edb65
|
|
@ -831,6 +831,60 @@ export default defineConfig({
|
|||
// Demo script not yet created — skip
|
||||
}
|
||||
}
|
||||
|
||||
// ── Generate precache manifest ──
|
||||
// Scans dist/ for all cacheable assets and writes precache-manifest.json
|
||||
const { readdirSync, writeFileSync, statSync: statSync2 } = await import("node:fs");
|
||||
const distDir = resolve(__dirname, "dist");
|
||||
|
||||
function walkDir(dir: string, prefix = ""): string[] {
|
||||
const entries: string[] = [];
|
||||
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
||||
const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
|
||||
if (entry.isDirectory()) {
|
||||
entries.push(...walkDir(resolve(dir, entry.name), rel));
|
||||
} else {
|
||||
entries.push(`/${rel}`);
|
||||
}
|
||||
}
|
||||
return entries;
|
||||
}
|
||||
|
||||
const allFiles = walkDir(distDir);
|
||||
|
||||
// Core: shell assets + HTML pages (precached at install, ~300KB)
|
||||
const core = allFiles.filter((f) =>
|
||||
f === "/" ||
|
||||
f === "/index.html" ||
|
||||
f === "/canvas.html" ||
|
||||
f === "/create-space.html" ||
|
||||
f === "/admin.html" ||
|
||||
f === "/shell.js" ||
|
||||
f === "/shell.css" ||
|
||||
f === "/theme.css" ||
|
||||
f === "/favicon.png"
|
||||
);
|
||||
// Ensure root URL is present
|
||||
if (!core.includes("/")) core.unshift("/");
|
||||
|
||||
// Modules: all module JS + CSS (lazy-cached after activation)
|
||||
const modules = allFiles.filter((f) =>
|
||||
f.startsWith("/modules/") &&
|
||||
(f.endsWith(".js") || f.endsWith(".css")) &&
|
||||
!f.includes("-demo.js") // skip demo scripts
|
||||
);
|
||||
|
||||
const manifest = {
|
||||
version: new Date().toISOString(),
|
||||
core,
|
||||
modules,
|
||||
};
|
||||
|
||||
writeFileSync(
|
||||
resolve(distDir, "precache-manifest.json"),
|
||||
JSON.stringify(manifest, null, "\t"),
|
||||
);
|
||||
console.log(`[precache] Generated manifest: ${core.length} core + ${modules.length} module assets`);
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/// <reference lib="webworker" />
|
||||
declare const self: ServiceWorkerGlobalScope;
|
||||
|
||||
const CACHE_VERSION = "rspace-v1";
|
||||
const CACHE_VERSION = "rspace-v2";
|
||||
const STATIC_CACHE = `${CACHE_VERSION}-static`;
|
||||
const HTML_CACHE = `${CACHE_VERSION}-html`;
|
||||
const API_CACHE = `${CACHE_VERSION}-api`;
|
||||
|
|
@ -9,32 +9,75 @@ const API_CACHE = `${CACHE_VERSION}-api`;
|
|||
// Vite-hashed assets are immutable (content hash in filename)
|
||||
const IMMUTABLE_PATTERN = /\/assets\/.*\.[a-f0-9]{8}\.(js|css|wasm)$/;
|
||||
|
||||
// App shell to precache on install
|
||||
const PRECACHE_URLS = ["/", "/canvas.html"];
|
||||
// Minimal fallback if manifest fetch fails
|
||||
const FALLBACK_PRECACHE = ["/", "/canvas.html"];
|
||||
|
||||
// Max age for cached API GET responses (5 minutes)
|
||||
const API_CACHE_MAX_AGE_MS = 5 * 60 * 1000;
|
||||
|
||||
interface PrecacheManifest {
|
||||
version: string;
|
||||
core: string[]; // shell assets + HTML pages — cached at install
|
||||
modules: string[]; // module JS/CSS — lazy-cached after activation
|
||||
}
|
||||
|
||||
self.addEventListener("install", (event) => {
|
||||
event.waitUntil(
|
||||
caches.open(HTML_CACHE).then((cache) => cache.addAll(PRECACHE_URLS))
|
||||
(async () => {
|
||||
let manifest: PrecacheManifest | null = null;
|
||||
try {
|
||||
const res = await fetch(`/precache-manifest.json?v=${CACHE_VERSION}`);
|
||||
if (res.ok) manifest = await res.json();
|
||||
} catch { /* manifest unavailable — use fallback */ }
|
||||
|
||||
const coreUrls = manifest?.core ?? FALLBACK_PRECACHE;
|
||||
|
||||
// Precache core shell assets (blocking — required for cold offline start)
|
||||
const htmlCache = await caches.open(HTML_CACHE);
|
||||
const staticCache = await caches.open(STATIC_CACHE);
|
||||
|
||||
const htmlUrls = coreUrls.filter((u) => u.endsWith(".html") || u === "/");
|
||||
const staticUrls = coreUrls.filter((u) => !u.endsWith(".html") && u !== "/");
|
||||
|
||||
await Promise.all([
|
||||
htmlCache.addAll(htmlUrls),
|
||||
staticCache.addAll(staticUrls),
|
||||
]);
|
||||
})()
|
||||
);
|
||||
self.skipWaiting();
|
||||
});
|
||||
|
||||
self.addEventListener("activate", (event) => {
|
||||
// Clean up old versioned caches
|
||||
event.waitUntil(
|
||||
caches
|
||||
.keys()
|
||||
.then((keys) =>
|
||||
Promise.all(
|
||||
keys
|
||||
.filter((key) => !key.startsWith(CACHE_VERSION))
|
||||
.map((key) => caches.delete(key))
|
||||
)
|
||||
)
|
||||
.then(() => self.clients.claim())
|
||||
(async () => {
|
||||
// Clean up old versioned caches
|
||||
const keys = await caches.keys();
|
||||
await Promise.all(
|
||||
keys
|
||||
.filter((key) => !key.startsWith(CACHE_VERSION))
|
||||
.map((key) => caches.delete(key))
|
||||
);
|
||||
await self.clients.claim();
|
||||
|
||||
// Lazy-cache module bundles in background (non-blocking)
|
||||
try {
|
||||
const res = await fetch(`/precache-manifest.json?v=${CACHE_VERSION}`);
|
||||
if (res.ok) {
|
||||
const manifest: PrecacheManifest = await res.json();
|
||||
if (manifest.modules?.length) {
|
||||
const cache = await caches.open(STATIC_CACHE);
|
||||
// Cache modules one-by-one to avoid overwhelming bandwidth
|
||||
for (const url of manifest.modules) {
|
||||
try {
|
||||
const existing = await cache.match(url);
|
||||
if (!existing) await cache.add(url);
|
||||
} catch { /* skip individual failures */ }
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch { /* manifest unavailable */ }
|
||||
})()
|
||||
);
|
||||
});
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue