From d008f655bce55f9d9f4cf63be4b7441e80262529 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bal=C3=A1zs=20Orb=C3=A1n?= Date: Fri, 5 Aug 2022 23:28:17 +0200 Subject: [PATCH] fix: skip resizing image if it's animated (#39325) We were resizing animated images when importing them, but we don't optimize images when they come from an upstream provider. For consistency, we can skip resizing for local animated images as well. Fixes #39317 ## Bug - [ ] Related issues linked using `fixes #number` - [ ] Integration tests added - [ ] Errors have helpful link attached, see `contributing.md` ## Feature - [ ] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR. - [ ] Related issues linked using `fixes #number` - [ ] Integration tests added - [ ] Documentation added - [ ] Telemetry added. In case of a feature if it's used or not. - [ ] Errors have helpful link attached, see `contributing.md` ## Documentation / Examples - [ ] Make sure the linting passes by running `pnpm lint` - [ ] The examples guidelines are followed from [our contributing doc](https://github.com/vercel/next.js/blob/canary/contributing.md#adding-examples) --- packages/next/server/image-optimizer.ts | 5 ++- packages/next/types/misc.d.ts | 4 ++ .../image-optimizer/app/pages/index.js | 37 ++++++++++++++++--- .../test/{index.test.js => index.test.ts} | 2 +- .../{old-sharp.test.js => old-sharp.test.ts} | 0 .../test/{sharp.test.js => sharp.test.ts} | 0 .../test/{squoosh.test.js => squoosh.test.ts} | 0 .../image-optimizer/test/{util.js => util.ts} | 17 ++++----- 8 files changed, 47 insertions(+), 18 deletions(-) rename test/integration/image-optimizer/test/{index.test.js => index.test.ts} (99%) rename test/integration/image-optimizer/test/{old-sharp.test.js => old-sharp.test.ts} (100%) rename test/integration/image-optimizer/test/{sharp.test.js => sharp.test.ts} (100%) rename test/integration/image-optimizer/test/{squoosh.test.js => squoosh.test.ts} (100%) rename test/integration/image-optimizer/test/{util.js => util.ts} (99%) diff --git a/packages/next/server/image-optimizer.ts b/packages/next/server/image-optimizer.ts index c6c2267cc322..b26cef8d074a 100644 --- a/packages/next/server/image-optimizer.ts +++ b/packages/next/server/image-optimizer.ts @@ -4,7 +4,6 @@ import { promises } from 'fs' import { getOrientation, Orientation } from 'next/dist/compiled/get-orientation' import imageSizeOf from 'next/dist/compiled/image-size' import { IncomingMessage, ServerResponse } from 'http' -// @ts-ignore no types for is-animated import isAnimated from 'next/dist/compiled/is-animated' import contentDisposition from 'next/dist/compiled/content-disposition' import { join } from 'path' @@ -726,7 +725,9 @@ export async function resizeImage( extension: 'avif' | 'webp' | 'png' | 'jpeg', quality: number ): Promise { - if (sharp) { + if (isAnimated(content)) { + return content + } else if (sharp) { const transformer = sharp(content) if (extension === 'avif') { diff --git a/packages/next/types/misc.d.ts b/packages/next/types/misc.d.ts index 34504bc08589..131c9577276f 100644 --- a/packages/next/types/misc.d.ts +++ b/packages/next/types/misc.d.ts @@ -367,3 +367,7 @@ declare module 'next/dist/compiled/watchpack' { export default Watchpack } + +declare module 'next/dist/compiled/is-animated' { + export default function isAnimated(buffer: Buffer): boolean +} diff --git a/test/integration/image-optimizer/app/pages/index.js b/test/integration/image-optimizer/app/pages/index.js index faab57ef7881..91cc59719fe9 100644 --- a/test/integration/image-optimizer/app/pages/index.js +++ b/test/integration/image-optimizer/app/pages/index.js @@ -1,13 +1,40 @@ import Image from 'next/image' -import Logo from '../public/test.jpg' -function Home() { +import img1 from '../public/animated2.png' +import img2 from '../public/äöüščří.png' +import img3 from '../public/test.avif' +import img4 from '../public/test.jpg' +import img5 from '../public/test.webp' +import img6 from '../public/animated.gif' +import img7 from '../public/grayscale.png' +import img8 from '../public/test.bmp' +import img9 from '../public/test.png' +import img11 from '../public/animated.png' +import img12 from '../public/mountains.jpg' +import img13 from '../public/test.gif' +import img14 from '../public/test.svg' +import img15 from '../public/animated.webp' +import img17 from '../public/test.ico' + +export default function Home() { return ( <>

Image Optimizer Home

- + + + + + + + + + + + + + + + ) } - -export default Home diff --git a/test/integration/image-optimizer/test/index.test.js b/test/integration/image-optimizer/test/index.test.ts similarity index 99% rename from test/integration/image-optimizer/test/index.test.js rename to test/integration/image-optimizer/test/index.test.ts index 6ba13e347cf6..4a07414bc1a1 100644 --- a/test/integration/image-optimizer/test/index.test.js +++ b/test/integration/image-optimizer/test/index.test.ts @@ -374,7 +374,7 @@ describe('Image Optimizer', () => { describe('Server support for minimumCacheTTL in next.config.js', () => { const size = 96 // defaults defined in server/config.ts const dangerouslyAllowSVG = true - const ctx = { + const ctx: any = { w: size, isDev: false, domains, diff --git a/test/integration/image-optimizer/test/old-sharp.test.js b/test/integration/image-optimizer/test/old-sharp.test.ts similarity index 100% rename from test/integration/image-optimizer/test/old-sharp.test.js rename to test/integration/image-optimizer/test/old-sharp.test.ts diff --git a/test/integration/image-optimizer/test/sharp.test.js b/test/integration/image-optimizer/test/sharp.test.ts similarity index 100% rename from test/integration/image-optimizer/test/sharp.test.js rename to test/integration/image-optimizer/test/sharp.test.ts diff --git a/test/integration/image-optimizer/test/squoosh.test.js b/test/integration/image-optimizer/test/squoosh.test.ts similarity index 100% rename from test/integration/image-optimizer/test/squoosh.test.js rename to test/integration/image-optimizer/test/squoosh.test.ts diff --git a/test/integration/image-optimizer/test/util.js b/test/integration/image-optimizer/test/util.ts similarity index 99% rename from test/integration/image-optimizer/test/util.js rename to test/integration/image-optimizer/test/util.ts index a972b447202c..b79a061ce86f 100644 --- a/test/integration/image-optimizer/test/util.js +++ b/test/integration/image-optimizer/test/util.ts @@ -40,11 +40,8 @@ export async function serveSlowImage() { res.end(await fs.readFile(join(__dirname, '../app/public/test.png'))) }) - await new Promise((resolve, reject) => { - server.listen(port, (err) => { - if (err) return reject(err) - resolve() - }) + await new Promise((resolve) => { + server.listen(port, () => resolve(true)) }) console.log(`Started slow image server at ::${port}`) return { @@ -129,7 +126,7 @@ async function fetchWithDuration(...args) { export function runTests(ctx) { const { isDev, minimumCacheTTL = 60 } = ctx - let slowImageServer + let slowImageServer: Awaited> beforeAll(async () => { slowImageServer = await serveSlowImage() }) @@ -1248,7 +1245,7 @@ export const setupTests = (ctx) => { await cleanImagesDir(ctx) }) afterAll(async () => { - await killApp(curCtx.app) + if (curCtx.app) await killApp(curCtx.app) }) runTests(curCtx) @@ -1288,8 +1285,8 @@ export const setupTests = (ctx) => { }) }) afterAll(async () => { - await killApp(curCtx.app) nextConfig.restore() + if (curCtx.app) await killApp(curCtx.app) }) runTests(curCtx) @@ -1321,7 +1318,7 @@ export const setupTests = (ctx) => { }) }) afterAll(async () => { - await killApp(curCtx.app) + if (curCtx.app) await killApp(curCtx.app) }) runTests(curCtx) @@ -1362,8 +1359,8 @@ export const setupTests = (ctx) => { }) }) afterAll(async () => { - await killApp(curCtx.app) nextConfig.restore() + if (curCtx.app) await killApp(curCtx.app) }) runTests(curCtx)