skyflytravel.hu/scripts/optimize-images.mjs

94 lines
2.2 KiB
JavaScript

import fs from "node:fs/promises";
import path from "node:path";
import sharp from "sharp";
const ROOT = process.cwd();
const TARGET_DIRS = ["public", "images"];
const SKIP_DIRS = new Set(["node_modules", ".next", "out", ".git"]);
const EXTENSIONS = new Set([".jpg", ".jpeg", ".png"]);
async function exists(p) {
try {
await fs.access(p);
return true;
} catch {
return false;
}
}
async function walk(dir, files = []) {
const entries = await fs.readdir(dir, { withFileTypes: true });
for (const entry of entries) {
const fullPath = path.join(dir, entry.name);
if (entry.isDirectory()) {
if (SKIP_DIRS.has(entry.name)) continue;
await walk(fullPath, files);
} else if (entry.isFile()) {
const ext = path.extname(entry.name).toLowerCase();
if (EXTENSIONS.has(ext)) {
files.push(fullPath);
}
}
}
return files;
}
async function optimizeImage(filePath) {
const ext = path.extname(filePath).toLowerCase();
const input = sharp(filePath);
const tempPath = `${filePath}.tmp`;
if (ext === ".png") {
await input.png({ compressionLevel: 9, adaptiveFiltering: true }).toFile(tempPath);
} else {
await input.jpeg({ quality: 82, mozjpeg: true }).toFile(tempPath);
}
const [origStat, tempStat] = await Promise.all([
fs.stat(filePath),
fs.stat(tempPath),
]);
if (tempStat.size <= origStat.size) {
await fs.rename(tempPath, filePath);
} else {
await fs.unlink(tempPath);
}
}
async function main() {
const targets = [];
for (const dir of TARGET_DIRS) {
const full = path.join(ROOT, dir);
if (await exists(full)) targets.push(full);
}
if (targets.length === 0) {
console.log("No image directories found (public/, images/).");
return;
}
const files = [];
for (const dir of targets) {
await walk(dir, files);
}
if (files.length === 0) {
console.log("No .jpg/.jpeg/.png files found.");
return;
}
console.log(`Optimizing ${files.length} images...`);
for (const file of files) {
try {
await optimizeImage(file);
} catch (err) {
console.warn(`Skipping ${file}: ${err?.message ?? err}`);
}
}
}
main().catch((err) => {
console.error(err);
process.exit(1);
});