Shumiland/scripts/optimize-images.mjs
Vadym Samoilenko 63af1f86e3 perf: add AVIF/WebP next image config and image optimization script
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-11 13:04:04 +01:00

49 lines
2 KiB
JavaScript

#!/usr/bin/env node
import fs from 'node:fs/promises'
import path from 'node:path'
import sharp from 'sharp'
const ROOT = path.resolve(process.cwd(), 'public/images/figma')
const QUALITY = 82
const MIN_BYTES = 200_000
const manifest = { deletedDuplicates: [], encoded: [], skipped: [] }
const all = await fs.readdir(ROOT)
const byBase = new Map()
for (const f of all) {
const ext = path.extname(f)
const base = ext ? path.basename(f, ext) : f
if (!byBase.has(base)) byBase.set(base, [])
byBase.get(base).push(f)
}
// 1) Delete extensionless duplicates that have a webp/png/jpg sibling
for (const [, variants] of byBase) {
const extensionless = variants.find((v) => path.extname(v) === '')
const hasSibling = variants.some((v) => /\.(webp|png|jpg|jpeg)$/i.test(v))
if (extensionless && hasSibling) {
const p = path.join(ROOT, extensionless)
await fs.unlink(p)
manifest.deletedDuplicates.push(path.basename(p))
}
}
// 2) Re-encode large png/jpg to webp (skip if webp already exists and is newer)
for (const [base, variants] of byBase) {
const heavy = variants.find((v) => /\.(png|jpg|jpeg)$/i.test(v))
if (!heavy) continue
const srcPath = path.join(ROOT, heavy)
const stat = await fs.stat(srcPath).catch(() => null)
if (!stat || stat.size < MIN_BYTES) { manifest.skipped.push(path.basename(srcPath)); continue }
const outPath = path.join(ROOT, `${base}.webp`)
const outStat = await fs.stat(outPath).catch(() => null)
if (outStat && outStat.mtimeMs > stat.mtimeMs) { manifest.skipped.push(path.basename(srcPath) + ' (webp newer)'); continue }
await sharp(srcPath).webp({ quality: QUALITY }).toFile(outPath)
manifest.encoded.push({ src: path.basename(srcPath), out: `${base}.webp`, before: stat.size })
}
const manifestPath = path.join(process.cwd(), 'scripts/optimize-images.manifest.json')
await fs.writeFile(manifestPath, JSON.stringify(manifest, null, 2))
console.log(`Deleted ${manifest.deletedDuplicates.length} duplicates, encoded ${manifest.encoded.length} files, skipped ${manifest.skipped.length}.`)
console.log('Manifest:', manifestPath)