import fs from 'node:fs/promises'; import path from 'node:path'; import sharp from 'sharp'; const roots = ['public', path.join('src', 'assets')]; async function walk(dir) { const entries = await fs.readdir(dir, { withFileTypes: true }); const files = await Promise.all( entries.map(async (entry) => { const fullPath = path.join(dir, entry.name); if (entry.isDirectory()) { return walk(fullPath); } return fullPath; }), ); return files.flat(); } function pickWidth(filePath) { const normalized = filePath.replace(/\\/g, '/'); if (normalized.includes('/images/blog/')) return 1280; if (normalized.endsWith('/hero-bg.png')) return 1600; if (normalized.endsWith('/process-illustration.png')) return 1600; if (normalized.includes('/assets/services/')) return 1200; return 1280; } async function optimize(filePath) { const targetPath = filePath.replace(/\.png$/i, '.webp'); const width = pickWidth(filePath); const image = sharp(filePath, { animated: false }).rotate(); const metadata = await image.metadata(); const pipeline = metadata.width && metadata.width > width ? image.resize({ width, withoutEnlargement: true }) : image; await pipeline.webp({ quality: 76, effort: 6 }).toFile(targetPath); } const pngFiles = ( await Promise.all( roots.map(async (root) => { try { return await walk(root); } catch { return []; } }), ) ) .flat() .filter((filePath) => filePath.toLowerCase().endsWith('.png')); await Promise.all(pngFiles.map((filePath) => optimize(filePath))); console.log(`Optimized ${pngFiles.length} PNG files to WebP.`);