From 3193c509a7605d12781973ca8c1e349b559892f4 Mon Sep 17 00:00:00 2001 From: Andras Schmelczer Date: Sun, 31 May 2026 15:44:32 +0100 Subject: [PATCH] FIx timeout --- scripts/generate-assets.mjs | 49 ++++++++++++++++++++++++++----------- 1 file changed, 35 insertions(+), 14 deletions(-) diff --git a/scripts/generate-assets.mjs b/scripts/generate-assets.mjs index a23f92a..673465f 100644 --- a/scripts/generate-assets.mjs +++ b/scripts/generate-assets.mjs @@ -169,10 +169,17 @@ const generate = async () => { })); await assertCatalogMatchesFiles(catalog); - await rm(publicPhotoDir, { recursive: true, force: true }); await mkdir(publicPhotoDir, { recursive: true }); await mkdir(generatedDir, { recursive: true }); + // Variant filenames embed a hash of their source image, so any file that + // already exists is already up to date. Skip re-encoding those and prune + // only the ones no longer referenced. Regenerating every variant from + // scratch takes minutes and would blow the Playwright preview server's + // startup timeout. + const existingFiles = new Set(await readdir(publicPhotoDir)); + const expectedFiles = new Set(); + const photos = []; for (const entry of catalog) { @@ -192,8 +199,10 @@ const generate = async () => { const variants = outputWidths.map((width) => { const height = Math.round((width / metadata.width) * metadata.height); const filename = `${entry.id}-${hash}-${width}.${format.extension}`; + expectedFiles.add(filename); return { + filename, outputPath: path.join(publicPhotoDir, filename), src: `static/photos/${filename}`, width, @@ -202,20 +211,22 @@ const generate = async () => { }); await Promise.all( - variants.map(async ({ outputPath, width }) => { - const pipeline = sharp(input).rotate().resize({ - width, - withoutEnlargement: true, - }); + variants + .filter(({ filename }) => !existingFiles.has(filename)) + .map(async ({ outputPath, width }) => { + const pipeline = sharp(input).rotate().resize({ + width, + withoutEnlargement: true, + }); - if (format.extension === 'avif') { - await pipeline.avif(format.options).toFile(outputPath); - } else if (format.extension === 'webp') { - await pipeline.webp(format.options).toFile(outputPath); - } else { - await pipeline.jpeg(format.options).toFile(outputPath); - } - }) + if (format.extension === 'avif') { + await pipeline.avif(format.options).toFile(outputPath); + } else if (format.extension === 'webp') { + await pipeline.webp(format.options).toFile(outputPath); + } else { + await pipeline.jpeg(format.options).toFile(outputPath); + } + }) ); sources.push({ @@ -249,6 +260,16 @@ const generate = async () => { }); } + // Drop variants that are no longer referenced: deleted photos, or sources + // whose content changed (and so produced a new hash in their filename). + await Promise.all( + [...existingFiles] + .filter((filename) => !expectedFiles.has(filename)) + .map((filename) => + rm(path.join(publicPhotoDir, filename), { force: true }) + ) + ); + const firstPhoto = photos[0]; const portraits = photos .filter((photo) => photo.orientation === 'portrait')