Skip to content

Conversation

@tyminko
Copy link
Contributor

@tyminko tyminko commented Aug 10, 2025

🔧 Fix

Fixes #1918

Problem

When using image presets with defined sizes, the preset sizes are not applied if the component's sizes prop is undefined. This causes fallback to density-based srcset instead of the expected width-based srcset from presets.

Changes Made

  1. Enhanced getSizes function (src/runtime/image.ts):

    • Added proper preset merging using defu
    • Ensures preset sizes and densities are used when not overridden by component props
  2. Updated components (NuxtImg.vue, NuxtPicture.vue):

    • Only pass sizes and densities props when explicitly defined (!== undefined)
    • Prevents undefined from overriding preset values
  3. Added tests:

    • Test for preset sizes application when component sizes is undefined
    • Test for preset densities application when component densities is undefined

Before vs After

Before: /_ipx/s_300x400/image.png 1x, /_ipx/s_600x800/image.png 2x (density-based)
After: /_ipx/s_320x427/image.png 320w, /_ipx/s_640x853/image.png 640w, /_ipx/s_1024x1365/image.png 1024w (width-based from preset)

Testing

  • ✅ All existing tests pass (26/26 image tests)
  • ✅ New tests verify the fix works correctly
  • ✅ Linting passes (pnpm lint)
  • ✅ Build succeeds (pnpm build)
  • ✅ No regressions in core functionality

Breaking Changes

None. This is a bug fix that makes the behavior match the documented/expected behavior.

- Enhanced getSizes function to properly merge preset options using defu
- Updated NuxtImg and NuxtPicture components to only pass sizes/densities when explicitly defined
- Added tests to verify preset sizes and densities are correctly applied
- Fixes issue where undefined props override preset values causing incorrect srcset generation

Resolves density-based fallback when width-based srcset should be used from presets

Fixes nuxt#1918
@tyminko tyminko requested a review from danielroe as a code owner August 10, 2025 15:18
@vercel
Copy link

vercel bot commented Aug 10, 2025

@tyminko is attempting to deploy a commit to the NuxtLabs Team on Vercel.

A member of the Team first needs to authorize it.

@pkg-pr-new
Copy link

pkg-pr-new bot commented Aug 10, 2025

Open in StackBlitz

npm i https://pkg.pr.new/@nuxt/image@1919

commit: 79fd5ef

return formats.map((format) => {
const { srcset, sizes, src } = $img.getSizes(props.src!, {
...providerOptions.value,
sizes: props.sizes || $img.options.screens,
Copy link
Member

@danielroe danielroe Oct 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it looks like we lose this behaviour - should we pass screens as a fallback in getSizes?

@codecov-commenter
Copy link

codecov-commenter commented Oct 30, 2025

Codecov Report

❌ Patch coverage is 0% with 7 lines in your changes missing coverage. Please review.
✅ Project coverage is 7.02%. Comparing base (b4b8b0e) to head (79fd5ef).
⚠️ Report is 2 commits behind head on main.

Files with missing lines Patch % Lines
src/runtime/image.ts 0.00% 7 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff            @@
##            main   #1919      +/-   ##
========================================
- Coverage   7.03%   7.02%   -0.02%     
========================================
  Files         77      77              
  Lines       3567    3573       +6     
  Branches     138     138              
========================================
  Hits         251     251              
- Misses      3268    3274       +6     
  Partials      48      48              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

expect(img.html()).toMatchInlineSnapshot(`
"<picture>
<source type="image/webp" sizes="(max-width: 768px) 640px, (max-width: 1024px) 768px, (max-width: 1280px) 1024px, (max-width: 1536px) 1280px, 1536px" srcset="/_ipx/f_webp&amp;s_640x640/image.png 640w, /_ipx/f_webp&amp;s_768x768/image.png 768w, /_ipx/f_webp&amp;s_1024x1024/image.png 1024w, /_ipx/f_webp&amp;s_1280x1280/image.png 1280w, /_ipx/f_webp&amp;s_1536x1536/image.png 1536w, /_ipx/f_webp&amp;s_2048x2048/image.png 2048w, /_ipx/f_webp&amp;s_2560x2560/image.png 2560w, /_ipx/f_webp&amp;s_3072x3072/image.png 3072w"><img width="200" height="200" data-nuxt-pic="" src="/_ipx/f_png&amp;s_3072x3072/image.png" sizes="(max-width: 768px) 640px, (max-width: 1024px) 768px, (max-width: 1280px) 1024px, (max-width: 1536px) 1280px, 1536px" srcset="/_ipx/f_png&amp;s_640x640/image.png 640w, /_ipx/f_png&amp;s_768x768/image.png 768w, /_ipx/f_png&amp;s_1024x1024/image.png 1024w, /_ipx/f_png&amp;s_1280x1280/image.png 1280w, /_ipx/f_png&amp;s_1536x1536/image.png 1536w, /_ipx/f_png&amp;s_2048x2048/image.png 2048w, /_ipx/f_png&amp;s_2560x2560/image.png 2560w, /_ipx/f_png&amp;s_3072x3072/image.png 3072w">
<source type="image/webp" srcset="/_ipx/f_webp&amp;s_200x200/image.png 1x, /_ipx/f_webp&amp;s_400x400/image.png 2x"><img width="200" height="200" data-nuxt-pic="" src="/_ipx/f_png&amp;s_400x400/image.png" srcset="/_ipx/f_png&amp;s_200x200/image.png 1x, /_ipx/f_png&amp;s_400x400/image.png 2x">
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added a test to show that omitting $img.screens changes behaviour

Copy link
Member

@danielroe danielroe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thank you!

happy to follow up with another PR to discuss how to use screens as a default (either in img or picture).

I'm aware that preset sizes still do not override screens (for <NuxtPicture>) and this needs more attention.

@danielroe danielroe merged commit 7c0555d into nuxt:main Oct 31, 2025
7 checks passed
This was referenced Oct 30, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Preset sizes not applied when component sizes prop is undefined

3 participants