← back to Homesonspec
apps/web/scripts/gen-pwa-icons.mjs
37 lines
// Rasterize public/icon.svg into the PWA/iOS icon sizes.
// Uses `sharp` (already in the workspace pnpm store) — no new packages, no network.
// pnpm doesn't hoist sharp into apps/web, so resolve it by absolute path from the repo root.
// Run: node scripts/gen-pwa-icons.mjs
import { readFile, writeFile } from "node:fs/promises";
import { fileURLToPath } from "node:url";
import { dirname, join } from "node:path";
import { createRequire } from "node:module";
const here = dirname(fileURLToPath(import.meta.url));
const publicDir = join(here, "..", "public");
const repoRoot = join(here, "..", "..", "..");
// Find sharp in the pnpm store and require it (CJS) by absolute directory path.
const require = createRequire(join(repoRoot, "package.json"));
const sharpDir = join(repoRoot, "node_modules/.pnpm/sharp@0.34.5/node_modules/sharp");
const sharp = require(sharpDir);
const svg = await readFile(join(publicDir, "icon.svg"));
// name, size, background (null = transparent). iOS touch icons must be opaque.
const targets = [
{ file: "icon-192.png", size: 192, bg: null },
{ file: "icon-512.png", size: 512, bg: null },
{ file: "apple-touch-icon.png", size: 180, bg: "#1b4645" },
{ file: "favicon-32.png", size: 32, bg: null },
];
for (const t of targets) {
let img = sharp(svg, { density: 384 }).resize(t.size, t.size, { fit: "cover" });
if (t.bg) img = img.flatten({ background: t.bg });
const out = await img.png().toBuffer();
await writeFile(join(publicDir, t.file), out);
console.log(`✓ ${t.file} (${t.size}×${t.size}, ${out.length} bytes)`);
}
console.log("done");