119 lines
3.3 KiB
JavaScript
119 lines
3.3 KiB
JavaScript
const sharp = require('sharp');
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
const optimizeImage = async (inputPath, outputPath, options = {}) => {
|
|
const {
|
|
quality = 80,
|
|
width,
|
|
height,
|
|
format = 'webp'
|
|
} = options;
|
|
|
|
try {
|
|
let pipeline = sharp(inputPath);
|
|
|
|
if (width || height) {
|
|
pipeline = pipeline.resize(width, height, {
|
|
fit: 'inside',
|
|
withoutEnlargement: true
|
|
});
|
|
}
|
|
|
|
switch (format) {
|
|
case 'webp':
|
|
pipeline = pipeline.webp({ quality });
|
|
break;
|
|
case 'avif':
|
|
pipeline = pipeline.avif({ quality });
|
|
break;
|
|
case 'jpeg':
|
|
pipeline = pipeline.jpeg({ quality });
|
|
break;
|
|
case 'png':
|
|
pipeline = pipeline.png({ quality });
|
|
break;
|
|
}
|
|
|
|
await pipeline.toFile(outputPath);
|
|
|
|
const inputStats = fs.statSync(inputPath);
|
|
const outputStats = fs.statSync(outputPath);
|
|
const savings = ((inputStats.size - outputStats.size) / inputStats.size * 100).toFixed(2);
|
|
|
|
console.log(`✅ Optimized: ${path.basename(inputPath)}`);
|
|
console.log(` Original: ${(inputStats.size / 1024 / 1024).toFixed(2)}MB`);
|
|
console.log(` Optimized: ${(outputStats.size / 1024 / 1024).toFixed(2)}MB`);
|
|
console.log(` Savings: ${savings}%`);
|
|
console.log('');
|
|
} catch (error) {
|
|
console.error(`❌ Failed to optimize ${inputPath}:`, error.message);
|
|
}
|
|
};
|
|
|
|
const optimizeDirectory = async (dirPath) => {
|
|
const files = fs.readdirSync(dirPath);
|
|
|
|
for (const file of files) {
|
|
const filePath = path.join(dirPath, file);
|
|
const stat = fs.statSync(filePath);
|
|
|
|
if (stat.isDirectory()) {
|
|
await optimizeDirectory(filePath);
|
|
} else if (stat.isFile()) {
|
|
const ext = path.extname(file).toLowerCase();
|
|
if (['.jpg', '.jpeg', '.png', '.gif'].includes(ext)) {
|
|
const fileSize = stat.size / 1024 / 1024; // MB
|
|
|
|
// Only optimize files larger than 100KB
|
|
if (fileSize > 0.1) {
|
|
const outputPath = filePath.replace(ext, '.webp');
|
|
|
|
// Determine optimal dimensions based on file size
|
|
let targetWidth, targetHeight;
|
|
if (fileSize > 5) { // Very large files
|
|
targetWidth = 1920;
|
|
targetHeight = 1080;
|
|
} else if (fileSize > 1) { // Large files
|
|
targetWidth = 1200;
|
|
targetHeight = 800;
|
|
} else if (fileSize > 0.5) { // Medium files
|
|
targetWidth = 800;
|
|
targetHeight = 600;
|
|
}
|
|
|
|
await optimizeImage(filePath, outputPath, {
|
|
quality: 80,
|
|
width: targetWidth,
|
|
height: targetHeight,
|
|
format: 'webp'
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
// Optimize specific problematic directories
|
|
const optimizeProject = async () => {
|
|
console.log('🚀 Starting image optimization...\n');
|
|
|
|
const directories = [
|
|
'public/assets',
|
|
'public/images/all-img',
|
|
'public/images/users',
|
|
'public/images/avatar'
|
|
];
|
|
|
|
for (const dir of directories) {
|
|
if (fs.existsSync(dir)) {
|
|
console.log(`📁 Processing directory: ${dir}`);
|
|
await optimizeDirectory(dir);
|
|
}
|
|
}
|
|
|
|
console.log('✅ Image optimization complete!');
|
|
};
|
|
|
|
// Run the optimization
|
|
optimizeProject().catch(console.error);
|