Images inside <template [tag]> are not generated during nuxt generate, but work in development mode
I have encountered a problem with the @nuxt/image module when using it inside a <template> tag. Images are not generated correctly when running nuxt generate, although they work fine in development mode ( nuxt dev ).
<UPopover :popper="{ placement: 'bottom-end' }">
<UButton icon="bi:globe-americas"/>
<template #panel>
<NuxtImg
src="/img/example.webp"
width="25"
format="webp"
densities="x1 x2"
/>
</template>
</UPopover>
When running nuxt dev - the image will be displayed correctly.
When I run nuxt generate and try to open the page, the image is not generated and the browser shows a 404 error http://localhost:3000/_ipx/f_webp/img/example.webp
<template #panel>
Expected behavior: The image should be generated and available during static generation, similar to how it works in development mode.
The image is not generated during static site generation and the page shows a 404 error when trying to load the image. However, the image works fine when running nuxt dev.
package.json
"dependencies": {
"@nuxt/ui": "^2.19.2",
"@nuxtjs/i18n": "^9.0.0",
"axios": "^1.7.7",
"lodash": "^4.17.21",
"nuxt": "^3.14.159",
"nuxt-zod-i18n": "^1.10.0",
"vue": "latest",
"vue-router": "latest",
"zod": "^3.23.8"
},
"devDependencies": {
"@nuxt/image": "^1.8.1",
"nuxt-aos": "^1.2.5",
"nuxt-swiper": "^2.0.0",
"sass-embedded": "^1.81.0"
}
Additional information: This issue seems to be related specifically to the use of NuxtImg inside a tag with a named slot ( #panel in this case).
The images work fine in development mode, but are not generated during static build.
I have verified that the images are correctly placed.
When I remove the slot ( without #panel), the image is generated correctly during static build. But adding #panel or any other gives an error.
Did you manage to solve the issue?
Did you manage to solve the issue?
no (
[!NOTE] Please see here for a better solution
I wrote a utility to manually collect all possible images:
interface ImageOptions {
width: number
height: number
sizes?: string
}
export function ensureGenImages(urls: string[], opts?: ImageOptions) {
if (!import.meta.server)
return
const img = useImage()
const { width, height, sizes } = opts || {}
urls.forEach((url) => {
if (opts) {
const srcset = img.getSizes(url, { modifiers: { width, height }, sizes })
// we don't need this in deed, see another comment below
extractUrls(srcset.srcset).forEach((url) => {
$fetch(url)
})
}
else {
// we don't need the `$fetch` call in deed, see another comment below
$fetch(img(url))
}
})
}
function extractUrls(srcset: string) {
return srcset.split(',').map(s => s.trim().split(' ')[0])
}
The fetch will cause ipx to generate images...
The not graceful place is that you need to extract the imageOptions(width,height,sizes) or double writing code. But I didn't find a way to avoid this...
And you need to call this utility function at somewhere always render.
It's already a solution, thanks for sharing.
I found that practically the $fetch call has no effect. What make this work are img call and img.getSizes call, so a more simple code:
interface ImageOptions {
width: number
height: number
sizes?: string
}
export function ensureGenImages(urls: string[], opts?: ImageOptions) {
if (!import.meta.server || !import.meta.prerender)
return
const img = useImage()
const { width, height, sizes } = opts || {}
urls.forEach((url) => {
if (opts) {
img.getSizes(url, { modifiers: { width, height }, sizes })
}
else {
img(url)
}
})
}
It's already a solution, thanks for sharing.
已经有解决方案了,谢谢分享。
请问是什么解决方案,谢谢