/** * SW PRECACHE 自动生成:post-build 按 dist 产物推导路由清单,重写 dist/sw.js * 兜底段(AUTO-BEGIN/END 标记之间)。规则:顶层路由 + /en/ 轨(路径段 ≤1, * 排除 /en 自身段计数),排除 /admin(CMS 非离线内容)。新增顶层页自动入列—— * 根治手工清单漏页(Phase 5e 维护债)。 */ import { readdirSync, readFileSync, writeFileSync, statSync, existsSync } from 'node:fs'; import { join } from 'node:path'; const dist = process.argv[2] ?? 'dist'; const swPath = join(dist, 'sw.js'); const routes = []; // dist 下所有 index.html → 站点路由(目录名映射) function walk(dir, prefix) { for (const name of readdirSync(dir)) { const full = join(dir, name); if (!statSync(full).isDirectory()) continue; if (name === 'admin') continue; // CMS 不进离线包 walk(full, `${prefix}/${name}`); } if (prefix && existsSync(join(dir, 'index.html'))) { const segs = prefix.replace(/^\/en(?=\/|$)/, '').split('/').filter(Boolean); if (segs.length <= 1) routes.push(prefix.endsWith('/') ? prefix : `${prefix}/`); } } walk(dist, ''); routes.sort(); const sw = readFileSync(swPath, 'utf-8'); const re = /(\/\/ PRECACHE:AUTO-BEGIN[\s\S]*?const PRECACHE = \[)[\s\S]*?(\];\n\/\/ PRECACHE:AUTO-END)/; if (!re.test(sw)) { console.error('[gen-sw-precache] sw.js 缺少 AUTO 标记,跳过(保持兜底清单)'); process.exit(0); } const list = routes.map((r) => ` '${r}',`).join('\n'); const next = sw.replace(re, `$1\n${list}\n$2`); writeFileSync(swPath, next); console.log(`[gen-sw-precache] ${routes.length} 路由入预缓存: ${routes.slice(0, 4).join(' ')}${routes.length > 4 ? ' …' : ''}`);