Skip to content

Commit e311acc

Browse files
perf(nuxt): improve decoding handling
1 parent a24c66e commit e311acc

File tree

2 files changed

+45
-43
lines changed

2 files changed

+45
-43
lines changed

packages/nuxt/playground/app.vue

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ function loadImage() {
3030
src-set="image-320w.jpg 320w, image-640w.jpg 640w"
3131
width="640"
3232
height="320"
33+
style="aspect-ratio: 1/1;"
3334
/>
3435
<p class="text-sm text-gray-500">
3536
The image above is inlined as a PNG data URI.
@@ -43,6 +44,7 @@ function loadImage() {
4344
src-set="image-320w.jpg 320w, image-640w.jpg 640w"
4445
width="640"
4546
height="320"
47+
style="aspect-ratio: 1/1;"
4648
/>
4749
<p class="text-sm text-gray-500">
4850
The client-side decoded BlurHash will infer the image dimensions from the <code>width</code> and <code>height</code> attributes.

packages/nuxt/src/runtime/components/UnLazyImage.vue

Lines changed: 43 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
<script setup lang="ts">
2-
import { lazyLoad } from 'unlazy'
3-
import { createPngDataUri as createPngDataUriFromThumbHash } from 'unlazy/thumbhash'
4-
import { createPngDataUri as createPngDataUriFromBlurHash } from 'unlazy/blurhash'
2+
import { createPlaceholderFromHash, lazyLoad } from 'unlazy'
53
import type { ImgHTMLAttributes } from 'vue'
6-
import { computed, onBeforeUnmount, onMounted, ref, useRuntimeConfig, watchEffect } from '#imports'
4+
import { onBeforeUnmount, ref, useRuntimeConfig, watchEffect } from '#imports'
75
86
const props = withDefaults(
97
defineProps<{
@@ -55,47 +53,49 @@ const props = withDefaults(
5553
},
5654
)
5755
56+
// SSR-decoded BlurHash as PNG data URI placeholder image
5857
const { unlazy } = useRuntimeConfig().public
58+
const hash = props.thumbhash || props.blurhash
59+
const loadSSR = process.server && (props.ssr ?? unlazy.ssr)
60+
const pngPlaceholder = (loadSSR && hash)
61+
? createPlaceholderFromHash({
62+
hash,
63+
hashType: props.thumbhash ? 'thumbhash' : 'blurhash',
64+
size: props.placeholderSize || unlazy.placeholderSize,
65+
ratio: props.placeholderRatio,
66+
})
67+
: undefined
68+
5969
const target = ref<HTMLImageElement | undefined>()
60-
let isLoaded = false
6170
let cleanup: () => void | undefined
71+
let hasPlaceholder = false
6272
63-
// SSR-decoded BlurHash as PNG data URI placeholder image
64-
const pngPlaceholder = computed(() => {
65-
if (
66-
(process.client || (props.ssr ?? unlazy.ssr))
67-
&& (props.blurhash || props.thumbhash)
68-
) {
69-
return props.blurhash
70-
? createPngDataUriFromBlurHash(props.blurhash, {
71-
size: props.placeholderSize || unlazy.placeholderSize,
72-
ratio: props.placeholderRatio,
73-
})
74-
: createPngDataUriFromThumbHash(props.thumbhash!)
75-
}
76-
})
73+
watchEffect(() => {
74+
cleanup?.()
7775
78-
onMounted(() => {
7976
if (!target.value)
8077
return
8178
82-
watchEffect(() => {
83-
cleanup?.()
84-
85-
if (pngPlaceholder.value && !isLoaded)
86-
target.value!.src = pngPlaceholder.value
87-
88-
if (!props.lazyLoad)
89-
return
90-
91-
cleanup = lazyLoad(target.value!, {
79+
if (!hasPlaceholder) {
80+
const placeholder = createPlaceholderFromHash({
81+
image: target.value,
9282
hash: props.thumbhash || props.blurhash,
9383
hashType: props.thumbhash ? 'thumbhash' : 'blurhash',
94-
placeholderSize: props.placeholderSize || unlazy.placeholderSize,
84+
size: props.placeholderSize || unlazy.placeholderSize,
85+
ratio: props.placeholderRatio,
9586
})
9687
97-
isLoaded = true
98-
})
88+
if (placeholder)
89+
target.value.src = placeholder
90+
91+
hasPlaceholder = true
92+
}
93+
94+
if (!props.lazyLoad)
95+
return
96+
97+
// Placeholder is already decoded
98+
cleanup = lazyLoad(target.value, { hash: false })
9999
})
100100
101101
onBeforeUnmount(() => {
@@ -104,16 +104,7 @@ onBeforeUnmount(() => {
104104
</script>
105105

106106
<template>
107-
<img
108-
v-if="!props.sources?.length"
109-
ref="target"
110-
:src="pngPlaceholder || placeholderSrc"
111-
:data-src="src"
112-
:data-srcset="srcSet"
113-
:data-sizes="autoSizes ? 'auto' : undefined"
114-
loading="lazy"
115-
>
116-
<picture v-else>
107+
<picture v-if="props.sources?.length">
117108
<source
118109
v-for="(source, index) in props.sources"
119110
:key="index"
@@ -130,4 +121,13 @@ onBeforeUnmount(() => {
130121
loading="lazy"
131122
>
132123
</picture>
124+
<img
125+
v-else
126+
ref="target"
127+
:src="pngPlaceholder || placeholderSrc"
128+
:data-src="src"
129+
:data-srcset="srcSet"
130+
:data-sizes="autoSizes ? 'auto' : undefined"
131+
loading="lazy"
132+
>
133133
</template>

0 commit comments

Comments
 (0)