Stage 3: offline/PWA foundation — SW registration + minimal shell SW
- Normalize branch to main - public/sw.js: hand-written, tiny (install precache + activate cleanup + fetch navigation/assets cache-first + package passthrough /latest.json /editions/** C-21 + message SKIP_WAITING). Safe population: open+addAll atomically, delete partial on failure; versioned cache lumen-shell-<version>-<gitHash> deterministic per build (injected via Vite plugin, not static); no skipWaiting in install (next full start per ARCH §8), no IDB/sync/dataset/B-5 - public/fallback.html: Ring-0 last-resort, no IDB, preserves future emergency baseline (src/emergency-baseline remains empty until Stage 10) - src/platform/sw/register.ts: offline-safe bridge, never blocks boot, scope /, handles unsupported/failed, skipWaitingForUpdate - src/app/main.ts: import + void registerSW().catch (non-blocking) - vite.config.ts: lumenShellPlugin closeBundle injects CACHE_NAME + PRECACHE_URLS (core /, index.html, fallback.html, manifest, icons + hashed assets/*) + precache-manifest.json; hashed immutable assets via rollup output - Build: dist/index.html 0.92kB, style 3.06kB/1.18gz, js 8.15kB/2.74gz (shell <1MB/150kB budgets) - Tests: tests/unit/sw.test.ts (16 tests: file minimal, B-5, install/activate/fetch/message, package passthrough, fallback last-resort, registration unsupported/registered/failed, skipWaiting, versioning) - CI: typecheck + lint + format + test (34 tests) + build — desktop automation; iOS lifecycle/persistence/eviction/jetsam/install still physical-device validation per ARCHITECTURE-VALIDATION.md §4
This commit is contained in:
parent
902a1ffc22
commit
615ae2565c
7 changed files with 418 additions and 10 deletions
|
|
@ -1,4 +1,59 @@
|
|||
import { defineConfig } from "vite";
|
||||
import { defineConfig, type Plugin } from "vite";
|
||||
import { readdirSync, readFileSync, writeFileSync, existsSync } from "node:fs";
|
||||
import { join } from "node:path";
|
||||
import { execSync } from "node:child_process";
|
||||
|
||||
function lumenShellPlugin(): Plugin {
|
||||
return {
|
||||
name: "lumen-shell-precache",
|
||||
closeBundle() {
|
||||
const dist = "dist";
|
||||
const swPath = join(dist, "sw.js");
|
||||
if (!existsSync(swPath)) return;
|
||||
|
||||
// Deterministic version: package version + short git hash (if available)
|
||||
let gitHash = "dev";
|
||||
try {
|
||||
gitHash = execSync("git rev-parse --short=8 HEAD", { stdio: ["ignore", "pipe", "ignore"] })
|
||||
.toString()
|
||||
.trim();
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
const pkg = JSON.parse(readFileSync("package.json", "utf8")) as { version: string };
|
||||
const version = `${pkg.version}-${gitHash}`;
|
||||
const cacheName = `lumen-shell-${version}`;
|
||||
|
||||
// Collect hashed assets produced by this build
|
||||
const assetsDir = join(dist, "assets");
|
||||
const assetFiles = existsSync(assetsDir) ? readdirSync(assetsDir) : [];
|
||||
const hashedAssets = assetFiles.map((f) => `/assets/${f}`);
|
||||
|
||||
// Core shell URLs that must be precached (deterministic list per build)
|
||||
const core = [
|
||||
"/",
|
||||
"/index.html",
|
||||
"/fallback.html",
|
||||
"/manifest.webmanifest",
|
||||
"/icon.png",
|
||||
"/icon-192.png",
|
||||
"/icon-512.png",
|
||||
];
|
||||
const precache = [...core, ...hashedAssets];
|
||||
|
||||
let sw = readFileSync(swPath, "utf8");
|
||||
sw = sw.replace(/const CACHE_NAME = "lumen-shell-v1";/, `const CACHE_NAME = "${cacheName}";`);
|
||||
sw = sw.replace(
|
||||
/const PRECACHE_URLS = \[[\s\S]*?\];/,
|
||||
`const PRECACHE_URLS = ${JSON.stringify(precache, null, 2)};`,
|
||||
);
|
||||
// Also write precache manifest for debugging / future SW tooling
|
||||
const manifestPath = join(dist, "precache-manifest.json");
|
||||
writeFileSync(manifestPath, JSON.stringify({ cacheName, precache }, null, 2));
|
||||
writeFileSync(swPath, sw);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export default defineConfig({
|
||||
appType: "spa",
|
||||
|
|
@ -6,6 +61,7 @@ export default defineConfig({
|
|||
port: 5173,
|
||||
strictPort: true,
|
||||
},
|
||||
plugins: [lumenShellPlugin()],
|
||||
build: {
|
||||
outDir: "dist",
|
||||
assetsDir: "assets",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue