diff --git a/docs/basic-features/image-optimization.md b/docs/basic-features/image-optimization.md index f7ce5c5d92230..a972027481639 100644 --- a/docs/basic-features/image-optimization.md +++ b/docs/basic-features/image-optimization.md @@ -15,7 +15,7 @@ Since version **10.0.0**, Next.js has a built-in Image Component and Automatic I The Next.js Image Component, [`next/image`](/docs/api-reference/next/image.md), is an extension of the HTML `` element, evolved for the modern web. -The Automatic Image Optimization allows for resizing, optimizing, and serving images in modern formats like [WebP](https://developer.mozilla.org/en-US/docs/Web/Media/Formats/Image_types) when the browser supports it. This avoids shipping large images to devices with a smaller viewport. It also allows Next.js to automatically adopt future image formats and serve them to browsers that support those formats. +The Automatic Image Optimization allows for resizing, optimizing, and serving images in modern formats like [AVIF and WebP](https://developer.mozilla.org/en-US/docs/Web/Media/Formats/Image_types) when the browser supports it. This avoids shipping large images to devices with a smaller viewport. It also allows Next.js to automatically adopt future image formats and serve them to browsers that support those formats. Automatic Image Optimization works with any image source. Even if the image is hosted by an external data source, like a CMS, it can still be optimized. diff --git a/docs/migrating/from-create-react-app.md b/docs/migrating/from-create-react-app.md index 7fe79aff932d0..28e5db58bd79a 100644 --- a/docs/migrating/from-create-react-app.md +++ b/docs/migrating/from-create-react-app.md @@ -89,7 +89,7 @@ Since version **10.0.0**, Next.js has a built-in [Image Component and Automatic The Next.js Image Component, [`next/image`](/docs/api-reference/next/image.md), is an extension of the HTML `` element, evolved for the modern web. -The Automatic Image Optimization allows for resizing, optimizing, and serving images in modern formats like [WebP](https://developer.mozilla.org/en-US/docs/Web/Media/Formats/Image_types) when the browser supports it. This avoids shipping large images to devices with a smaller viewport. It also allows Next.js to automatically adopt future image formats and serve them to browsers that support those formats. +The Automatic Image Optimization allows for resizing, optimizing, and serving images in modern formats like [AVIF and WebP](https://developer.mozilla.org/en-US/docs/Web/Media/Formats/Image_types) when the browser supports it. This avoids shipping large images to devices with a smaller viewport. It also allows Next.js to automatically adopt future image formats and serve them to browsers that support those formats. Instead of optimizing images at build time, Next.js optimizes images on-demand, as users request them. Your build times aren't increased, whether shipping 10 images or 10 million images. diff --git a/docs/migrating/from-gatsby.md b/docs/migrating/from-gatsby.md index 4601a7850ad8f..f672dbfd3c230 100644 --- a/docs/migrating/from-gatsby.md +++ b/docs/migrating/from-gatsby.md @@ -171,7 +171,7 @@ Since version **10.0.0**, Next.js has a built-in [Image Component and Automatic The Next.js Image Component, [`next/image`](/docs/api-reference/next/image.md), is an extension of the HTML `` element, evolved for the modern web. -The Automatic Image Optimization allows for resizing, optimizing, and serving images in modern formats like [WebP](https://developer.mozilla.org/en-US/docs/Web/Media/Formats/Image_types) when the browser supports it. This avoids shipping large images to devices with a smaller viewport. It also allows Next.js to automatically adopt future image formats and serve them to browsers that support those formats. +The Automatic Image Optimization allows for resizing, optimizing, and serving images in modern formats like [AVIF and WebP](https://developer.mozilla.org/en-US/docs/Web/Media/Formats/Image_types) when the browser supports it. This avoids shipping large images to devices with a smaller viewport. It also allows Next.js to automatically adopt future image formats and serve them to browsers that support those formats. ### Migrating from Gatsby Image diff --git a/packages/next/server/image-optimizer.ts b/packages/next/server/image-optimizer.ts index 5ded690e69cca..c4497afc44925 100644 --- a/packages/next/server/image-optimizer.ts +++ b/packages/next/server/image-optimizer.ts @@ -17,14 +17,14 @@ import { sendEtagResponse } from './send-payload' import { getContentType, getExtension } from './serve-static' import chalk from 'chalk' -//const AVIF = 'image/avif' +const AVIF = 'image/avif' const WEBP = 'image/webp' const PNG = 'image/png' const JPEG = 'image/jpeg' const GIF = 'image/gif' const SVG = 'image/svg+xml' const CACHE_VERSION = 3 -const MODERN_TYPES = [/* AVIF, */ WEBP] +const MODERN_TYPES = [AVIF, WEBP] const ANIMATABLE_TYPES = [WEBP, PNG, GIF] const VECTOR_TYPES = [SVG] const BLUR_IMG_SIZE = 8 // should match `next-image-loader` @@ -352,7 +352,9 @@ export async function imageOptimizer( transformer.resize(width) } - if (contentType === WEBP) { + if (contentType === AVIF) { + transformer.avif({ quality }) + } else if (contentType === WEBP) { transformer.webp({ quality }) } else if (contentType === PNG) { transformer.png({ quality }) diff --git a/test/integration/image-optimizer/app/public/test.avif b/test/integration/image-optimizer/app/public/test.avif new file mode 100644 index 0000000000000..866421faf29a2 Binary files /dev/null and b/test/integration/image-optimizer/app/public/test.avif differ diff --git a/test/integration/image-optimizer/test/index.test.js b/test/integration/image-optimizer/test/index.test.js index 9bde62dc650f2..fceace7b5c5b6 100644 --- a/test/integration/image-optimizer/test/index.test.js +++ b/test/integration/image-optimizer/test/index.test.js @@ -319,21 +319,44 @@ function runTests({ w, isDev, domains = [], ttl, isSharp }) { // FIXME: await expectWidth(res, w) }) - it('should resize relative url and Chrome accept header as webp', async () => { - const query = { url: '/test.png', w, q: 80 } - const opts = { - headers: { accept: 'image/avif,image/webp,image/apng,image/*,*/*;q=0.8' }, - } - const res = await fetchViaHTTP(appPort, '/_next/image', query, opts) - expect(res.status).toBe(200) - expect(res.headers.get('Content-Type')).toBe('image/webp') - expect(res.headers.get('Cache-Control')).toBe( - `public, max-age=0, must-revalidate` - ) - expect(res.headers.get('Vary')).toBe('Accept') - expect(res.headers.get('etag')).toBeTruthy() - await expectWidth(res, w) - }) + if (!isSharp) { + it('should resize relative url and Chrome accept header as webp', async () => { + const query = { url: '/test.png', w, q: 80 } + const opts = { + headers: { + accept: 'image/avif,image/webp,image/apng,image/*,*/*;q=0.8', + }, + } + const res = await fetchViaHTTP(appPort, '/_next/image', query, opts) + expect(res.status).toBe(200) + expect(res.headers.get('Content-Type')).toBe('image/webp') + expect(res.headers.get('Cache-Control')).toBe( + `public, max-age=0, must-revalidate` + ) + expect(res.headers.get('Vary')).toBe('Accept') + expect(res.headers.get('etag')).toBeTruthy() + await expectWidth(res, w) + }) + } + + if (isSharp) { + it('should resize relative url and Chrome accept header as avif', async () => { + const query = { url: '/test.png', w, q: 80 } + const opts = { + headers: { + accept: 'image/avif,image/webp,image/apng,image/*,*/*;q=0.8', + }, + } + const res = await fetchViaHTTP(appPort, '/_next/image', query, opts) + expect(res.status).toBe(200) + expect(res.headers.get('Content-Type')).toBe('image/avif') + expect(res.headers.get('cache-control')).toBe( + 'public, max-age=0, must-revalidate' + ) + expect(res.headers.get('etag')).toBeTruthy() + // FIXME: await expectWidth(res, w) + }) + } if (domains.includes('localhost')) { it('should resize absolute url from localhost', async () => {