49 lines
1.7 KiB
JavaScript
49 lines
1.7 KiB
JavaScript
|
|
// Generate WebP variants of source PNGs in public/product/.
|
||
|
|
// Run after replacing/adding a source PNG; outputs are committed.
|
||
|
|
//
|
||
|
|
// For each <name>.png we emit:
|
||
|
|
// <name>-1280.webp (q=82, used as inline srcset for desktop ≤ ~1280 px)
|
||
|
|
// <name>-1920.webp (q=80, used as inline srcset for retina/wide viewports
|
||
|
|
// and as the lightbox-modal full-size source)
|
||
|
|
//
|
||
|
|
// The original .png is kept as a <picture> fallback for the rare browser
|
||
|
|
// without WebP support (~2 % globally).
|
||
|
|
|
||
|
|
import { readdir, stat } from 'node:fs/promises';
|
||
|
|
import { join, parse } from 'node:path';
|
||
|
|
import { fileURLToPath } from 'node:url';
|
||
|
|
import sharp from 'sharp';
|
||
|
|
|
||
|
|
const SRC_DIR = fileURLToPath(new URL('../public/product/', import.meta.url));
|
||
|
|
|
||
|
|
const VARIANTS = [
|
||
|
|
{ width: 1280, quality: 82, suffix: '-1280' },
|
||
|
|
{ width: 1920, quality: 80, suffix: '-1920' },
|
||
|
|
];
|
||
|
|
|
||
|
|
const entries = await readdir(SRC_DIR);
|
||
|
|
const pngs = entries.filter((f) => f.toLowerCase().endsWith('.png'));
|
||
|
|
|
||
|
|
if (pngs.length === 0) {
|
||
|
|
console.error(`No PNGs found in ${SRC_DIR}`);
|
||
|
|
process.exit(1);
|
||
|
|
}
|
||
|
|
|
||
|
|
for (const file of pngs) {
|
||
|
|
const { name } = parse(file);
|
||
|
|
const inputPath = join(SRC_DIR, file);
|
||
|
|
const inputBytes = (await stat(inputPath)).size;
|
||
|
|
console.log(`\n${file} (${(inputBytes / 1024).toFixed(0)} KiB)`);
|
||
|
|
|
||
|
|
for (const v of VARIANTS) {
|
||
|
|
const outName = `${name}${v.suffix}.webp`;
|
||
|
|
const outPath = join(SRC_DIR, outName);
|
||
|
|
const info = await sharp(inputPath)
|
||
|
|
.resize({ width: v.width, withoutEnlargement: true })
|
||
|
|
.webp({ quality: v.quality, effort: 6 })
|
||
|
|
.toFile(outPath);
|
||
|
|
const pct = ((1 - info.size / inputBytes) * 100).toFixed(0);
|
||
|
|
console.log(` → ${outName} ${(info.size / 1024).toFixed(0)} KiB (-${pct}%)`);
|
||
|
|
}
|
||
|
|
}
|