import sharp from 'sharp'; import { readdir, mkdir } from 'fs/promises'; import { join, dirname, basename, extname } from 'path'; import { fileURLToPath } from 'url'; import { existsSync } from 'fs'; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); const SIZES = [400, 800, 1200]; const INPUT_DIR = join(__dirname, '../source-images/projects'); const OUTPUT_DIR = join(__dirname, '../public/images/projects'); async function processImage(inputPath, projectSlug) { const filename = basename(inputPath, extname(inputPath)); const ext = extname(inputPath).toLowerCase(); // Skip non-image files if (!['.jpg', '.jpeg', '.png', '.webp'].includes(ext)) { return; } const outputDir = join(OUTPUT_DIR, projectSlug); // Create output directory if it doesn't exist await mkdir(outputDir, { recursive: true }); console.log(`Processing: ${projectSlug}/${filename}${ext}`); // Create optimized original size (cover.jpg) const originalOutputPath = join(outputDir, `${filename}.jpg`); try { await sharp(inputPath) .jpeg({ quality: 85, progressive: true }) .toFile(originalOutputPath); console.log(` Created: ${filename}.jpg (optimized original)`); } catch (error) { console.error(` Error creating optimized original:`, error.message); } // Create different sizes for (const width of SIZES) { const outputFilename = `${filename}-${width}w.jpg`; const outputPath = join(outputDir, outputFilename); try { await sharp(inputPath) .resize(width, null, { withoutEnlargement: true, fit: 'inside' }) .jpeg({ quality: 80, progressive: true }) .toFile(outputPath); console.log(` Created: ${outputFilename}`); } catch (error) { console.error(` Error creating ${outputFilename}:`, error.message); } } // Create WebP version of original size const webpFilename = `${filename}.webp`; const webpPath = join(outputDir, webpFilename); try { await sharp(inputPath) .webp({ quality: 80 }) .toFile(webpPath); console.log(` Created: ${webpFilename}`); } catch (error) { console.error(` Error creating WebP:`, error.message); } } async function processDirectory(dirPath) { if (!existsSync(dirPath)) { console.error(`Error: Source directory not found: ${dirPath}`); console.log('\nPlease ensure original images are placed in:'); console.log(' source-images/projects//cover.jpg'); process.exit(1); } const entries = await readdir(dirPath, { withFileTypes: true }); for (const entry of entries) { const fullPath = join(dirPath, entry.name); if (entry.isDirectory()) { // Check for cover.jpg in this project directory const coverPath = join(fullPath, 'cover.jpg'); if (existsSync(coverPath)) { await processImage(coverPath, entry.name); } else { console.log(`Skipping ${entry.name}: no cover.jpg found`); } } } } async function main() { console.log('Starting image optimization...'); console.log(`Source: ${INPUT_DIR}`); console.log(`Output: ${OUTPUT_DIR}\n`); try { await processDirectory(INPUT_DIR); console.log('\nImage optimization complete!'); } catch (error) { console.error('Error during optimization:', error); process.exit(1); } } main();