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)
This commit is contained in:
Balázs Orbán 2022-08-05 23:28:17 +02:00 committed by GitHub
parent 442378d21d
commit d008f655bc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 47 additions and 18 deletions

View file

@ -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<Buffer> {
if (sharp) {
if (isAnimated(content)) {
return content
} else if (sharp) {
const transformer = sharp(content)
if (extension === 'avif') {

View file

@ -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
}

View file

@ -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 (
<>
<h1>Image Optimizer Home</h1>
<Image src={Logo} />
<Image src={img1} />
<Image src={img2} />
<Image src={img3} />
<Image src={img4} />
<Image src={img5} />
<Image src={img6} />
<Image src={img7} />
<Image src={img8} />
<Image src={img9} />
<Image src={img11} />
<Image src={img12} />
<Image src={img13} />
<Image src={img14} />
<Image src={img15} />
<Image src={img17} />
</>
)
}
export default Home

View file

@ -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,

View file

@ -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<ReturnType<typeof serveSlowImage>>
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)