Files
Fam Zheng bcf99ec454
deploy werewolf / build-and-deploy (push) Successful in 1m1s
werewolf(pwa): 离线 PWA — 自定义 SW 预缓存 + 全屏进度条,牌图 21M→2.8M
- vite-plugin-pwa(injectManifest)自定义 SW:install 逐个抓取并向页面广播进度,
  cache-first 服务,导航离线回退 index.html,缓存版本随清单哈希自动淘汰旧缓存
- 全屏 modal 进度条(src/pwa.ts),反映首屏预缓存真实下载进度
- 牌图 mozjpeg 压缩 + 限长边 900px,每张 ≤200K(21.2MB→2.8MB)
- 生成 PWA 图标 + manifest + apple-touch meta,index.html 接入
- 新增脚本:npm run gen:icons / compress:images
2026-05-25 18:44:46 +01:00

61 lines
2.1 KiB
JavaScript

// 把 public/werewolf 下的牌图压到每张 <= 200KB(原地覆盖)。
// 策略:最长边限 900px,mozjpeg 质量从高到低递减,直到达标。
// 已经 <= 目标的文件跳过,避免重复编码反复掉质量。
// 运行: npm run compress:images
import sharp from 'sharp'
import { readdir, stat, writeFile } from 'node:fs/promises'
import { fileURLToPath } from 'node:url'
import { dirname, resolve, join } from 'node:path'
const here = dirname(fileURLToPath(import.meta.url))
const root = resolve(here, '../public/werewolf')
const TARGET = 200 * 1024
const MAX_EDGE = 900
const QUALITIES = [82, 76, 70, 64, 58, 52, 46]
async function listJpgs(dir) {
const out = []
for (const name of await readdir(dir, { withFileTypes: true })) {
const p = join(dir, name.name)
if (name.isDirectory()) out.push(...(await listJpgs(p)))
else if (/\.jpe?g$/i.test(name.name)) out.push(p)
}
return out
}
async function compress(file) {
const before = (await stat(file)).size
if (before <= TARGET) return { file, skipped: true, before }
let chosen = null
for (const quality of QUALITIES) {
const buf = await sharp(file)
.rotate() // 按 EXIF 摆正
.resize({ width: MAX_EDGE, height: MAX_EDGE, fit: 'inside', withoutEnlargement: true })
.jpeg({ quality, mozjpeg: true })
.toBuffer()
chosen = { buf, quality }
if (buf.length <= TARGET) break
}
await writeFile(file, chosen.buf)
return { file, before, after: chosen.buf.length, quality: chosen.quality }
}
const files = await listJpgs(root)
let totalBefore = 0
let totalAfter = 0
for (const f of files) {
const r = await compress(f)
const rel = f.slice(root.length + 1)
if (r.skipped) {
totalBefore += r.before
totalAfter += r.before
console.log(`skip ${rel} (${(r.before / 1024) | 0}K)`)
} else {
totalBefore += r.before
totalAfter += r.after
console.log(`ok ${rel} ${(r.before / 1024) | 0}K -> ${(r.after / 1024) | 0}K q${r.quality}`)
}
}
console.log(`\n${files.length} files: ${(totalBefore / 1024 / 1024).toFixed(1)}MB -> ${(totalAfter / 1024 / 1024).toFixed(1)}MB`)