Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 19 additions & 10 deletions packages/next/src/shared/lib/get-img-props.ts
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ export function getImgProps(
{
src,
sizes,
unoptimized = false,
unoptimized,
priority = false,
preload = false,
loading,
Expand Down Expand Up @@ -417,13 +417,17 @@ export function getImgProps(
!priority &&
!preload &&
(loading === 'lazy' || typeof loading === 'undefined')

const unoptimizedProvided = typeof unoptimized !== 'undefined'
let shouldUnoptimize = Boolean(unoptimized)

if (!src || src.startsWith('data:') || src.startsWith('blob:')) {
// https://developer.mozilla.org/docs/Web/HTTP/Basics_of_HTTP/Data_URIs
unoptimized = true
shouldUnoptimize = true
isLazy = false
}
if (config.unoptimized) {
unoptimized = true
if (config.unoptimized && !unoptimizedProvided) {
shouldUnoptimize = true
}
if (
isDefaultLoader &&
Expand All @@ -432,13 +436,13 @@ export function getImgProps(
) {
// Special case to make svg serve as-is to avoid proxying
// through the built-in Image Optimization API.
unoptimized = true
shouldUnoptimize = true
}

const qualityInt = getInt(quality)

if (process.env.NODE_ENV !== 'production') {
if (config.output === 'export' && isDefaultLoader && !unoptimized) {
if (config.output === 'export' && isDefaultLoader && !shouldUnoptimize) {
throw new Error(
`Image Optimization using the default loader is not compatible with \`{ output: 'export' }\`.
Possible solutions:
Expand All @@ -451,7 +455,7 @@ export function getImgProps(
// React doesn't show the stack trace and there's
// no `src` to help identify which image, so we
// instead console.error(ref) during mount.
unoptimized = true
shouldUnoptimize = true
} else {
if (fill) {
if (width) {
Expand Down Expand Up @@ -580,7 +584,7 @@ export function getImgProps(
)
}

if (!unoptimized && !isDefaultLoader) {
if (!shouldUnoptimize && !isDefaultLoader) {
const urlStr = loader({
config,
src,
Expand Down Expand Up @@ -721,7 +725,7 @@ export function getImgProps(
const imgAttributes = generateImgAttrs({
config,
src,
unoptimized,
unoptimized: shouldUnoptimize,
width: widthInt,
quality: qualityInt,
sizes,
Expand Down Expand Up @@ -755,6 +759,11 @@ export function getImgProps(
srcSet: imgAttributes.srcSet,
src: overrideSrc || imgAttributes.src,
}
const meta = { unoptimized, preload: preload || priority, placeholder, fill }
const meta = {
unoptimized: shouldUnoptimize,
preload: preload || priority,
placeholder,
fill,
}
return { props, meta }
}
106 changes: 106 additions & 0 deletions test/unit/next-image-get-img-props.unoptimized-override.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
/* eslint-env jest */

import defaultLoader from '../../packages/next/src/shared/lib/image-loader'
import { imageConfigDefault } from '../../packages/next/src/shared/lib/image-config'
import { getImgProps } from '../../packages/next/src/shared/lib/get-img-props'

describe('getImgProps() unoptimized precedence', () => {
it('uses explicit unoptimized=false to override images.unoptimized=true', () => {
const { props, meta } = getImgProps(
{
alt: 'desc',
src: '/test.png',
width: 100,
height: 200,
unoptimized: false,
},
{
defaultLoader,
imgConf: { ...imageConfigDefault, unoptimized: true },
}
)
expect(meta.unoptimized).toBe(false)
expect(props.srcSet).toBeDefined()
expect(typeof props.srcSet).toBe('string')
expect(props.srcSet!.length).toBeGreaterThan(0)
})

it('inherits images.unoptimized=true when prop is not provided', () => {
const { props, meta } = getImgProps(
{
alt: 'desc',
src: '/test.png',
width: 100,
height: 200,
},
{
defaultLoader,
imgConf: { ...imageConfigDefault, unoptimized: true },
}
)
expect(meta.unoptimized).toBe(true)
expect(props.srcSet).toBeUndefined()
})

it('forces unoptimized for data URLs regardless of prop/config', () => {
const { props, meta } = getImgProps(
{
alt: 'desc',
src: 'data:image/png;base64,iVBORw0KGgo=',
width: 10,
height: 10,
unoptimized: false,
},
{
defaultLoader,
imgConf: { ...imageConfigDefault, unoptimized: false },
}
)
expect(meta.unoptimized).toBe(true)
expect(props.srcSet).toBeUndefined()
})

it('forces unoptimized for SVG with default loader when dangerouslyAllowSVG=false', () => {
const { props, meta } = getImgProps(
{
alt: 'desc',
src: '/icon.svg',
width: 24,
height: 24,
unoptimized: false,
},
{
defaultLoader,
imgConf: {
...imageConfigDefault,
dangerouslyAllowSVG: false,
unoptimized: false,
},
}
)
expect(meta.unoptimized).toBe(true)
expect(props.srcSet).toBeUndefined()
})

it('allows optimizing SVG when dangerouslyAllowSVG=true and unoptimized=false', () => {
const { props, meta } = getImgProps(
{
alt: 'desc',
src: '/icon.svg',
width: 24,
height: 24,
unoptimized: false,
},
{
defaultLoader,
imgConf: {
...imageConfigDefault,
dangerouslyAllowSVG: true,
unoptimized: false,
},
}
)
expect(meta.unoptimized).toBe(false)
expect(props.srcSet).toBeDefined()
})
})
Loading