diff --git a/.changeset/fix-animated-avif.md b/.changeset/fix-animated-avif.md new file mode 100644 index 000000000000..a7ec4ce26c68 --- /dev/null +++ b/.changeset/fix-animated-avif.md @@ -0,0 +1,5 @@ +--- +"astro": patch +--- + +Fixes build crash when processing animated AVIF images. Sharp now gracefully passes through unsupported image formats instead of crashing during the build. diff --git a/packages/astro/src/assets/services/sharp.ts b/packages/astro/src/assets/services/sharp.ts index 2e24d61662c1..f27012cd7b6f 100644 --- a/packages/astro/src/assets/services/sharp.ts +++ b/packages/astro/src/assets/services/sharp.ts @@ -156,9 +156,21 @@ const sharpService: LocalImageService = { // always call rotate to adjust for EXIF data orientation result.rotate(); - // get some information about the input - const { format } = await result.metadata(); + let format: string | undefined; + try { + ({ format } = await result.metadata()); + } catch { + // Sharp cannot decode this image (e.g. animated AVIF sequences). + // Pass it through unmodified rather than crashing the build. When Sharp adds support for these + // formats, the image will be optimized automatically without code changes. + console.warn( + `⚠️ Astro could not optimize image "${transform.src}". ` + + `Sharp doesn't support this format. The image will be used unoptimized. ` + + `Consider converting to WebP or placing in the public/ folder.` + ); + return { data: inputBuffer, format: transform.format }; + } if (transform.width && transform.height) { const fit: keyof FitEnum | undefined = transform.fit diff --git a/packages/astro/test/core-image.test.ts b/packages/astro/test/core-image.test.ts index 873ffe0fa937..19502e58ce40 100644 --- a/packages/astro/test/core-image.test.ts +++ b/packages/astro/test/core-image.test.ts @@ -1078,6 +1078,16 @@ describe('astro:image', () => { ); }); + it('animated avif does not crash the build', async () => { + const html = await fixture.readFile('/animated-avif/index.html'); + const $ = cheerio.load(html); + const src = $('#animated-avif img').attr('src')!; + assert.ok(src, 'expected img src to be set'); + const data = await fixture.readBuffer(src); + assert.equal(data instanceof Buffer, true); + assert.ok(data.byteLength > 0); + }); + it('markdown images are written', async () => { const html = await fixture.readFile('/post/index.html'); const $ = cheerio.load(html); diff --git a/packages/astro/test/fixtures/core-image-ssg/src/assets/animated.avif b/packages/astro/test/fixtures/core-image-ssg/src/assets/animated.avif new file mode 100644 index 000000000000..7c5738dba984 Binary files /dev/null and b/packages/astro/test/fixtures/core-image-ssg/src/assets/animated.avif differ diff --git a/packages/astro/test/fixtures/core-image-ssg/src/pages/animated-avif.astro b/packages/astro/test/fixtures/core-image-ssg/src/pages/animated-avif.astro new file mode 100644 index 000000000000..d0a08650dfd8 --- /dev/null +++ b/packages/astro/test/fixtures/core-image-ssg/src/pages/animated-avif.astro @@ -0,0 +1,11 @@ +--- +import { Image } from 'astro:assets'; +import animatedAvif from '../assets/animated.avif'; +--- + + +
+ animated avif +
+ +