Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: move src attribute to end of <img> tag to fix lazy loading (#1317) #1338

Merged
merged 2 commits into from
Apr 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/runtime/components/nuxt-img.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,11 +147,11 @@ export default defineComponent({

return () => h('img', {
ref: imgEl,
src: src.value,
...import.meta.server ? { onerror: 'this.setAttribute(\'data-error\', 1)' } : {},
...attrs.value,
...ctx.attrs,
class: props.placeholder && !placeholderLoaded.value ? [props.placeholderClass] : undefined,
src: src.value,
})
},
})
26 changes: 13 additions & 13 deletions test/unit/image.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ describe('Renders simple image', () => {
})

it('Matches snapshot', () => {
expect(wrapper.html()).toMatchInlineSnapshot('"<img src="/_ipx/s_1800x1800/image.png" width="200" height="200" data-nuxt-img="" sizes="(max-width: 500px) 200px, (max-width: 900px) 500px, 900px" srcset="/_ipx/s_200x200/image.png 200w, /_ipx/s_400x400/image.png 400w, /_ipx/s_500x500/image.png 500w, /_ipx/s_900x900/image.png 900w, /_ipx/s_1000x1000/image.png 1000w, /_ipx/s_1800x1800/image.png 1800w">"')
expect(wrapper.html()).toMatchInlineSnapshot(`"<img width="200" height="200" data-nuxt-img="" sizes="(max-width: 500px) 200px, (max-width: 900px) 500px, 900px" srcset="/_ipx/s_200x200/image.png 200w, /_ipx/s_400x400/image.png 400w, /_ipx/s_500x500/image.png 500w, /_ipx/s_900x900/image.png 900w, /_ipx/s_1000x1000/image.png 1000w, /_ipx/s_1800x1800/image.png 1800w" src="/_ipx/s_1800x1800/image.png">"`)
})

it('props.src is picked up by getImage()', () => {
Expand Down Expand Up @@ -52,7 +52,7 @@ describe('Renders simple image', () => {
densities: '1x 2x 3x',
src: 'image.png',
})
expect(img.html()).toMatchInlineSnapshot('"<img src="/_ipx/s_1200x1800/image.png" width="200" height="300" data-nuxt-img="" sizes="(max-width: 400px) 300px, 400px" srcset="/_ipx/s_300x450/image.png 300w, /_ipx/s_400x600/image.png 400w, /_ipx/s_600x900/image.png 600w, /_ipx/s_800x1200/image.png 800w, /_ipx/s_900x1350/image.png 900w, /_ipx/s_1200x1800/image.png 1200w">"')
expect(img.html()).toMatchInlineSnapshot(`"<img width="200" height="300" data-nuxt-img="" sizes="(max-width: 400px) 300px, 400px" srcset="/_ipx/s_300x450/image.png 300w, /_ipx/s_400x600/image.png 400w, /_ipx/s_600x900/image.png 600w, /_ipx/s_800x1200/image.png 800w, /_ipx/s_900x1350/image.png 900w, /_ipx/s_1200x1800/image.png 1200w" src="/_ipx/s_1200x1800/image.png">"`)
})

it('empty densities (fallback to global)', () => {
Expand All @@ -63,7 +63,7 @@ describe('Renders simple image', () => {
densities: '',
src: 'image.png',
})
expect(img.html()).toMatchInlineSnapshot('"<img src="/_ipx/s_800x1200/image.png" width="200" height="300" data-nuxt-img="" sizes="(max-width: 400px) 300px, 400px" srcset="/_ipx/s_300x450/image.png 300w, /_ipx/s_400x600/image.png 400w, /_ipx/s_600x900/image.png 600w, /_ipx/s_800x1200/image.png 800w">"')
expect(img.html()).toMatchInlineSnapshot(`"<img width="200" height="300" data-nuxt-img="" sizes="(max-width: 400px) 300px, 400px" srcset="/_ipx/s_300x450/image.png 300w, /_ipx/s_400x600/image.png 400w, /_ipx/s_600x900/image.png 600w, /_ipx/s_800x1200/image.png 800w" src="/_ipx/s_800x1200/image.png">"`)
})

it('empty string densities (fallback to global)', () => {
Expand All @@ -74,7 +74,7 @@ describe('Renders simple image', () => {
densities: ' ',
src: 'image.png',
})
expect(img.html()).toMatchInlineSnapshot('"<img src="/_ipx/s_800x1200/image.png" width="200" height="300" data-nuxt-img="" sizes="(max-width: 400px) 300px, 400px" srcset="/_ipx/s_300x450/image.png 300w, /_ipx/s_400x600/image.png 400w, /_ipx/s_600x900/image.png 600w, /_ipx/s_800x1200/image.png 800w">"')
expect(img.html()).toMatchInlineSnapshot(`"<img width="200" height="300" data-nuxt-img="" sizes="(max-width: 400px) 300px, 400px" srcset="/_ipx/s_300x450/image.png 300w, /_ipx/s_400x600/image.png 400w, /_ipx/s_600x900/image.png 600w, /_ipx/s_800x1200/image.png 800w" src="/_ipx/s_800x1200/image.png">"`)
})

it('error on invalid densities', () => {
Expand All @@ -93,7 +93,7 @@ describe('Renders simple image', () => {
height: 400,
sizes: '150',
})
expect(img.html()).toMatchInlineSnapshot('"<img src="/_ipx/s_300x400/image.png" width="300" height="400" data-nuxt-img="" sizes="150px" srcset="/_ipx/s_150x200/image.png 150w, /_ipx/s_300x400/image.png 300w">"')
expect(img.html()).toMatchInlineSnapshot(`"<img width="300" height="400" data-nuxt-img="" sizes="150px" srcset="/_ipx/s_150x200/image.png 150w, /_ipx/s_300x400/image.png 300w" src="/_ipx/s_300x400/image.png">"`)
})

it('with single sizes entry (responsive)', () => {
Expand All @@ -103,7 +103,7 @@ describe('Renders simple image', () => {
height: 400,
sizes: 'sm:150',
})
expect(img.html()).toMatchInlineSnapshot('"<img src="/_ipx/s_300x400/image.png" width="300" height="400" data-nuxt-img="" sizes="150px" srcset="/_ipx/s_150x200/image.png 150w, /_ipx/s_300x400/image.png 300w">"')
expect(img.html()).toMatchInlineSnapshot(`"<img width="300" height="400" data-nuxt-img="" sizes="150px" srcset="/_ipx/s_150x200/image.png 150w, /_ipx/s_300x400/image.png 300w" src="/_ipx/s_300x400/image.png">"`)
})

it('de-duplicates sizes & srcset', () => {
Expand All @@ -113,7 +113,7 @@ describe('Renders simple image', () => {
sizes: '200:200px,300:200px,400:400px,400:400px,500:500px,800:800px',
src: 'image.png',
})
expect(img.html()).toMatchInlineSnapshot('"<img src="/_ipx/s_1600x2400/image.png" width="200" height="300" data-nuxt-img="" sizes="(max-width: 300px) 200px, (max-width: 400px) 200px, (max-width: 500px) 400px, (max-width: 800px) 500px, 800px" srcset="/_ipx/s_200x300/image.png 200w, /_ipx/s_400x600/image.png 400w, /_ipx/s_500x750/image.png 500w, /_ipx/s_800x1200/image.png 800w, /_ipx/s_1000x1500/image.png 1000w, /_ipx/s_1600x2400/image.png 1600w">"')
expect(img.html()).toMatchInlineSnapshot(`"<img width="200" height="300" data-nuxt-img="" sizes="(max-width: 300px) 200px, (max-width: 400px) 200px, (max-width: 500px) 400px, (max-width: 800px) 500px, 800px" srcset="/_ipx/s_200x300/image.png 200w, /_ipx/s_400x600/image.png 400w, /_ipx/s_500x750/image.png 500w, /_ipx/s_800x1200/image.png 800w, /_ipx/s_1000x1500/image.png 1000w, /_ipx/s_1600x2400/image.png 1600w" src="/_ipx/s_1600x2400/image.png">"`)
})

it('encodes characters', () => {
Expand All @@ -123,7 +123,7 @@ describe('Renders simple image', () => {
sizes: '200,500:500,900:900',
src: '/汉字.png',
})
expect(img.html()).toMatchInlineSnapshot('"<img src="/_ipx/s_1800x1800/%E6%B1%89%E5%AD%97.png" width="200" height="200" data-nuxt-img="" sizes="(max-width: 500px) 200px, (max-width: 900px) 500px, 900px" srcset="/_ipx/s_200x200/%E6%B1%89%E5%AD%97.png 200w, /_ipx/s_400x400/%E6%B1%89%E5%AD%97.png 400w, /_ipx/s_500x500/%E6%B1%89%E5%AD%97.png 500w, /_ipx/s_900x900/%E6%B1%89%E5%AD%97.png 900w, /_ipx/s_1000x1000/%E6%B1%89%E5%AD%97.png 1000w, /_ipx/s_1800x1800/%E6%B1%89%E5%AD%97.png 1800w">"')
expect(img.html()).toMatchInlineSnapshot(`"<img width="200" height="200" data-nuxt-img="" sizes="(max-width: 500px) 200px, (max-width: 900px) 500px, 900px" srcset="/_ipx/s_200x200/%E6%B1%89%E5%AD%97.png 200w, /_ipx/s_400x400/%E6%B1%89%E5%AD%97.png 400w, /_ipx/s_500x500/%E6%B1%89%E5%AD%97.png 500w, /_ipx/s_900x900/%E6%B1%89%E5%AD%97.png 900w, /_ipx/s_1000x1000/%E6%B1%89%E5%AD%97.png 1000w, /_ipx/s_1800x1800/%E6%B1%89%E5%AD%97.png 1800w" src="/_ipx/s_1800x1800/%E6%B1%89%E5%AD%97.png">"`)
})

it('correctly sets crop', () => {
Expand All @@ -133,7 +133,7 @@ describe('Renders simple image', () => {
height: 2000,
sizes: 'xs:100vw sm:100vw md:300px lg:350px xl:350px 2xl:350px',
})
expect(img.html()).toMatchInlineSnapshot('"<img src="/_ipx/s_1280x2560/image.png" width="1000" height="2000" data-nuxt-img="" sizes="(max-width: 640px) 100vw, (max-width: 768px) 100vw, (max-width: 1024px) 300px, (max-width: 1280px) 350px, (max-width: 1536px) 350px, 350px" srcset="/_ipx/s_300x600/image.png 300w, /_ipx/s_320x640/image.png 320w, /_ipx/s_350x700/image.png 350w, /_ipx/s_600x1200/image.png 600w, /_ipx/s_640x1280/image.png 640w, /_ipx/s_700x1400/image.png 700w, /_ipx/s_1280x2560/image.png 1280w">"')
expect(img.html()).toMatchInlineSnapshot(`"<img width="1000" height="2000" data-nuxt-img="" sizes="(max-width: 640px) 100vw, (max-width: 768px) 100vw, (max-width: 1024px) 300px, (max-width: 1280px) 350px, (max-width: 1536px) 350px, 350px" srcset="/_ipx/s_300x600/image.png 300w, /_ipx/s_320x640/image.png 320w, /_ipx/s_350x700/image.png 350w, /_ipx/s_600x1200/image.png 600w, /_ipx/s_640x1280/image.png 640w, /_ipx/s_700x1400/image.png 700w, /_ipx/s_1280x2560/image.png 1280w" src="/_ipx/s_1280x2560/image.png">"`)
})

it('without sizes, but densities', () => {
Expand All @@ -143,7 +143,7 @@ describe('Renders simple image', () => {
height: 400,
densities: '1x 2x 3x',
})
expect(img.html()).toMatchInlineSnapshot('"<img src="/_ipx/s_300x400/image.png" width="300" height="400" data-nuxt-img="" srcset="/_ipx/s_300x400/image.png 1x, /_ipx/s_600x800/image.png 2x, /_ipx/s_900x1200/image.png 3x">"')
expect(img.html()).toMatchInlineSnapshot(`"<img width="300" height="400" data-nuxt-img="" srcset="/_ipx/s_300x400/image.png 1x, /_ipx/s_600x800/image.png 2x, /_ipx/s_900x1200/image.png 3x" src="/_ipx/s_300x400/image.png">"`)
})

it('with nonce', () => {
Expand Down Expand Up @@ -307,7 +307,7 @@ describe('Renders image, applies module config', () => {
sizes: '200,500:500,900:900',
},
})
expect(img.html()).toMatchInlineSnapshot('"<img src="/_ipx/q_75&s_1800x1800/image.png" width="200" height="200" data-nuxt-img="" sizes="(max-width: 500px) 200px, (max-width: 900px) 500px, 900px" srcset="/_ipx/q_75&s_200x200/image.png 200w, /_ipx/q_75&s_400x400/image.png 400w, /_ipx/q_75&s_500x500/image.png 500w, /_ipx/q_75&s_900x900/image.png 900w, /_ipx/q_75&s_1000x1000/image.png 1000w, /_ipx/q_75&s_1800x1800/image.png 1800w">"')
expect(img.html()).toMatchInlineSnapshot(`"<img width="200" height="200" data-nuxt-img="" sizes="(max-width: 500px) 200px, (max-width: 900px) 500px, 900px" srcset="/_ipx/q_75&s_200x200/image.png 200w, /_ipx/q_75&s_400x400/image.png 400w, /_ipx/q_75&s_500x500/image.png 500w, /_ipx/q_75&s_900x900/image.png 900w, /_ipx/q_75&s_1000x1000/image.png 1000w, /_ipx/q_75&s_1800x1800/image.png 1800w" src="/_ipx/q_75&s_1800x1800/image.png">"`)
})

it('Module config .quality + props.quality => props.quality applies', () => {
Expand All @@ -327,7 +327,7 @@ describe('Renders image, applies module config', () => {
quality: 90,
},
})
expect(img.html()).toMatchInlineSnapshot('"<img src="/_ipx/q_90&s_1800x1800/image.png" width="200" height="200" data-nuxt-img="" sizes="(max-width: 500px) 200px, (max-width: 900px) 500px, 900px" srcset="/_ipx/q_90&s_200x200/image.png 200w, /_ipx/q_90&s_400x400/image.png 400w, /_ipx/q_90&s_500x500/image.png 500w, /_ipx/q_90&s_900x900/image.png 900w, /_ipx/q_90&s_1000x1000/image.png 1000w, /_ipx/q_90&s_1800x1800/image.png 1800w">"')
expect(img.html()).toMatchInlineSnapshot(`"<img width="200" height="200" data-nuxt-img="" sizes="(max-width: 500px) 200px, (max-width: 900px) 500px, 900px" srcset="/_ipx/q_90&s_200x200/image.png 200w, /_ipx/q_90&s_400x400/image.png 400w, /_ipx/q_90&s_500x500/image.png 500w, /_ipx/q_90&s_900x900/image.png 900w, /_ipx/q_90&s_1000x1000/image.png 1000w, /_ipx/q_90&s_1800x1800/image.png 1800w" src="/_ipx/q_90&s_1800x1800/image.png">"`)
})

it('Without quality config => default image', () => {
Expand All @@ -345,7 +345,7 @@ describe('Renders image, applies module config', () => {
sizes: '200,500:500,900:900',
},
})
expect(img.html()).toMatchInlineSnapshot('"<img src="/_ipx/s_1800x1800/image.png" width="200" height="200" data-nuxt-img="" sizes="(max-width: 500px) 200px, (max-width: 900px) 500px, 900px" srcset="/_ipx/s_200x200/image.png 200w, /_ipx/s_400x400/image.png 400w, /_ipx/s_500x500/image.png 500w, /_ipx/s_900x900/image.png 900w, /_ipx/s_1000x1000/image.png 1000w, /_ipx/s_1800x1800/image.png 1800w">"')
expect(img.html()).toMatchInlineSnapshot(`"<img width="200" height="200" data-nuxt-img="" sizes="(max-width: 500px) 200px, (max-width: 900px) 500px, 900px" srcset="/_ipx/s_200x200/image.png 200w, /_ipx/s_400x400/image.png 400w, /_ipx/s_500x500/image.png 500w, /_ipx/s_900x900/image.png 900w, /_ipx/s_1000x1000/image.png 1000w, /_ipx/s_1800x1800/image.png 1800w" src="/_ipx/s_1800x1800/image.png">"`)
})
})

Expand Down