mirror of
https://github.com/hanzoai/next.js.git
synced 2026-09-24 17:00:51 +00:00
fix(next/image): improve warning when fill and sizes="100vw" (#61949)
Previously, this error was confusing because it made it sound like the `sizes` prop was missing. This was because the default value of `sizes` is `100vw` so the previous code couldn't tell the different between implicit vs explicit `100vw`. This PR changes the code to read the input value from the `sizes` prop and prints a better warning. Fixes NEXT-2441
This commit is contained in:
@@ -53,6 +53,7 @@ type ImageElementProps = ImgProps & {
|
||||
onLoadingCompleteRef: React.MutableRefObject<OnLoadingComplete | undefined>
|
||||
setBlurComplete: (b: boolean) => void
|
||||
setShowAltText: (b: boolean) => void
|
||||
sizesInput: string | undefined
|
||||
}
|
||||
|
||||
// See https://stackoverflow.com/q/39777833/266535 for why we use this ref
|
||||
@@ -63,7 +64,8 @@ function handleLoading(
|
||||
onLoadRef: React.MutableRefObject<OnLoad | undefined>,
|
||||
onLoadingCompleteRef: React.MutableRefObject<OnLoadingComplete | undefined>,
|
||||
setBlurComplete: (b: boolean) => void,
|
||||
unoptimized: boolean
|
||||
unoptimized: boolean,
|
||||
sizesInput: string | undefined
|
||||
) {
|
||||
const src = img?.src
|
||||
if (!img || img['data-loaded-src'] === src) {
|
||||
@@ -115,16 +117,19 @@ function handleLoading(
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
const origSrc = new URL(src, 'http://n').searchParams.get('url') || src
|
||||
if (img.getAttribute('data-nimg') === 'fill') {
|
||||
if (
|
||||
!unoptimized &&
|
||||
(!img.getAttribute('sizes') || img.getAttribute('sizes') === '100vw')
|
||||
) {
|
||||
if (!unoptimized && (!sizesInput || sizesInput === '100vw')) {
|
||||
let widthViewportRatio =
|
||||
img.getBoundingClientRect().width / window.innerWidth
|
||||
if (widthViewportRatio < 0.6) {
|
||||
warnOnce(
|
||||
`Image with src "${origSrc}" has "fill" but is missing "sizes" prop. Please add it to improve page performance. Read more: https://nextjs.org/docs/api-reference/next/image#sizes`
|
||||
)
|
||||
if (sizesInput === '100vw') {
|
||||
warnOnce(
|
||||
`Image with src "${origSrc}" has "fill" prop and "sizes" prop of "100vw", but image is not rendered at full viewport width. Please adjust "sizes" to improve page performance. Read more: https://nextjs.org/docs/api-reference/next/image#sizes`
|
||||
)
|
||||
} else {
|
||||
warnOnce(
|
||||
`Image with src "${origSrc}" has "fill" but is missing "sizes" prop. Please add it to improve page performance. Read more: https://nextjs.org/docs/api-reference/next/image#sizes`
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (img.parentElement) {
|
||||
@@ -197,6 +202,7 @@ const ImageElement = forwardRef<HTMLImageElement | null, ImageElementProps>(
|
||||
onLoadingCompleteRef,
|
||||
setBlurComplete,
|
||||
setShowAltText,
|
||||
sizesInput,
|
||||
onLoad,
|
||||
onError,
|
||||
...rest
|
||||
@@ -262,7 +268,8 @@ const ImageElement = forwardRef<HTMLImageElement | null, ImageElementProps>(
|
||||
onLoadRef,
|
||||
onLoadingCompleteRef,
|
||||
setBlurComplete,
|
||||
unoptimized
|
||||
unoptimized,
|
||||
sizesInput
|
||||
)
|
||||
}
|
||||
},
|
||||
@@ -274,6 +281,7 @@ const ImageElement = forwardRef<HTMLImageElement | null, ImageElementProps>(
|
||||
setBlurComplete,
|
||||
onError,
|
||||
unoptimized,
|
||||
sizesInput,
|
||||
forwardedRef,
|
||||
]
|
||||
)}
|
||||
@@ -285,7 +293,8 @@ const ImageElement = forwardRef<HTMLImageElement | null, ImageElementProps>(
|
||||
onLoadRef,
|
||||
onLoadingCompleteRef,
|
||||
setBlurComplete,
|
||||
unoptimized
|
||||
unoptimized,
|
||||
sizesInput
|
||||
)
|
||||
}}
|
||||
onError={(event) => {
|
||||
@@ -406,6 +415,7 @@ export const Image = forwardRef<HTMLImageElement | null, ImageProps>(
|
||||
onLoadingCompleteRef={onLoadingCompleteRef}
|
||||
setBlurComplete={setBlurComplete}
|
||||
setShowAltText={setShowAltText}
|
||||
sizesInput={props.sizes}
|
||||
ref={forwardedRef}
|
||||
/>
|
||||
}
|
||||
|
||||
@@ -28,6 +28,12 @@ const Page = () => {
|
||||
>
|
||||
<Image id="fill-image-3" src="/wide.png" fill />
|
||||
</div>
|
||||
<div
|
||||
id="image-container-4"
|
||||
style={{ position: 'relative', width: '30vw', height: '30vw' }}
|
||||
>
|
||||
<Image id="fill-image-4" src="/test.png" sizes="100vw" fill />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1318,6 +1318,9 @@ function runTests(mode) {
|
||||
expect(warnings).toContain(
|
||||
'Image with src "/wide.png" has "fill" but is missing "sizes" prop. Please add it to improve page performance. Read more:'
|
||||
)
|
||||
expect(warnings).toContain(
|
||||
'Image with src "/test.png" has "fill" prop and "sizes" prop of "100vw", but image is not rendered at full viewport width. Please adjust "sizes" to improve page performance. Read more:'
|
||||
)
|
||||
})
|
||||
it('should not log warnings when image unmounts', async () => {
|
||||
browser = await webdriver(appPort, '/should-not-warn-unmount')
|
||||
|
||||
@@ -28,6 +28,12 @@ const Page = () => {
|
||||
>
|
||||
<Image id="fill-image-3" src="/wide.png" fill />
|
||||
</div>
|
||||
<div
|
||||
id="image-container-4"
|
||||
style={{ position: 'relative', width: '30vw', height: '30vw' }}
|
||||
>
|
||||
<Image id="fill-image-4" src="/test.png" sizes="100vw" fill />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1319,6 +1319,9 @@ function runTests(mode) {
|
||||
expect(warnings).toContain(
|
||||
'Image with src "/wide.png" has "fill" but is missing "sizes" prop. Please add it to improve page performance. Read more:'
|
||||
)
|
||||
expect(warnings).toContain(
|
||||
'Image with src "/test.png" has "fill" prop and "sizes" prop of "100vw", but image is not rendered at full viewport width. Please adjust "sizes" to improve page performance. Read more:'
|
||||
)
|
||||
})
|
||||
it('should not log warnings when image unmounts', async () => {
|
||||
browser = await webdriver(appPort, '/should-not-warn-unmount')
|
||||
|
||||
Reference in New Issue
Block a user