Skip to content

Commit

Permalink
fix: apply sizes/srcset when using placeholder (#676)
Browse files Browse the repository at this point in the history
  • Loading branch information
Kolobok12309 authored Jun 7, 2023
1 parent d50d705 commit e1cc7bb
Show file tree
Hide file tree
Showing 4 changed files with 124 additions and 10 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ dist
coverage
sw.*
.vscode
.idea
.vercel
.output
30 changes: 25 additions & 5 deletions playground/pages/responsive.vue
Original file line number Diff line number Diff line change
Expand Up @@ -25,22 +25,42 @@
sizes="sm:100vw md:50vw lg:400px"
loading="lazy"
/>

<div style="width: 50vw; background-color: red">
i'm 50vw
</div>
<nuxt-img
src="/logos/nuxt.png"
sizes="sm:100vw md:50vw lg:400px"
placeholder
class="responsive-placeholder-img"
/>
</div>
</template>

<style scoped>
@media (max-width: 640px) {
img2 {
max-width: 100vw;
width: 100vw;
}
.responsive-placeholder-img {
width: 400px
}
@media (max-width: 768px) {
img2 {
max-width: 50vw;
width: 50vw;
}
.responsive-placeholder-img {
width: 50vw;
}
}
@media (max-width: 640px) {
img2 {
max-width: 100vw;
width: 100vw;
}
.responsive-placeholder-img {
width: 100vw;
}
}
img2 {
Expand Down
9 changes: 5 additions & 4 deletions src/runtime/components/nuxt-img.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export default defineComponent({

const attrs = computed(() => {
const attrs: AttrsT = { ..._base.attrs.value, 'data-nuxt-img': '' }
if (props.sizes) {
if (props.sizes && (!props.placeholder || placeholderLoaded.value)) {
attrs.sizes = sizes.value.sizes
attrs.srcset = sizes.value.srcset
}
Expand Down Expand Up @@ -101,10 +101,11 @@ export default defineComponent({
if (placeholder.value) {
const img = new Image()
img.src = mainSrc.value
if (props.sizes) {
img.sizes = sizes.value.sizes
img.srcset = sizes.value.srcset
}
img.onload = (event) => {
if (imgEl.value) {
imgEl.value.src = mainSrc.value
}
placeholderLoaded.value = true
ctx.emit('load', event)
}
Expand Down
94 changes: 93 additions & 1 deletion test/unit/image.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// @vitest-environment nuxt

import { beforeEach, describe, it, expect } from 'vitest'
import { beforeEach, describe, it, expect, vi } from 'vitest'
import { ComponentMountingOptions, VueWrapper, mount } from '@vue/test-utils'

import { NuxtImg } from '#components'
Expand Down Expand Up @@ -62,4 +62,96 @@ describe('Renders simple image', () => {
})
})

const getImageLoad = (cb = () => {}) => {
let resolve = () => {}
let image = {} as HTMLImageElement
const loadEvent = Symbol('loadEvent')
const ImageMock = vi.fn(() => {
const _image = {
onload: () => {}
} as unknown as HTMLImageElement
image = _image
// @ts-ignore
resolve = () => _image.onload?.(loadEvent)

return _image
})

vi.stubGlobal('Image', ImageMock)
cb()
vi.unstubAllGlobals()

return {
resolve,
image,
loadEvent
}
}

describe('Renders placeholded image', () => {
let wrapper: VueWrapper<any>
const src = '/image.png'

it('props.placeholder with src', async () => {
const {
resolve: resolveImage,
image: placeholderImage,
loadEvent
} = getImageLoad(() => {
wrapper = mount(NuxtImg, {
propsData: {
width: 200,
height: 200,
src,
placeholder: true
}
})
})

let domSrc = wrapper.find('img').element.getAttribute('src')

expect(domSrc).toMatchInlineSnapshot('"/_ipx/q_50&s_10x10/image.png"')
expect(placeholderImage.src).toMatchInlineSnapshot('"/_ipx/s_200x200/image.png"')

resolveImage()
await nextTick()

domSrc = wrapper.find('img').element.getAttribute('src')

expect(domSrc).toMatchInlineSnapshot('"/_ipx/s_200x200/image.png"')
expect(wrapper.emitted().load[0]).toStrictEqual([loadEvent])
})

it('props.placeholder with sizes', async () => {
const {
resolve: resolveImage,
image: placeholderImage,
loadEvent
} = getImageLoad(() => {
wrapper = mount(NuxtImg, {
propsData: {
width: 200,
height: 200,
src,
sizes: '200,500:500,900:900',
placeholder: true
}
})
})

let sizes = wrapper.find('img').element.getAttribute('sizes')

expect(sizes).toBe(null)
expect(placeholderImage.sizes).toBe('(max-width: 500px) 500px, 900px')

resolveImage()
await nextTick()

sizes = wrapper.find('img').element.getAttribute('sizes')

expect(sizes).toBe('(max-width: 500px) 500px, 900px')
expect(wrapper.emitted().load[0]).toStrictEqual([loadEvent])
})
})

const mountImage = (props: ComponentMountingOptions<typeof NuxtImg>['props']) => mount(NuxtImg, { props })

0 comments on commit e1cc7bb

Please sign in to comment.