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
Assets with dynamic names are not resolved #14766
Comments
I believe this is vite and @vitejs/plugin-vue behaviour. It's a bit complicated, but you can do this with https://stackblitz.com/edit/github-pq8nym-aoavsh <template>
<img :src="images[dynamic_image_name]" alt="Discover Nuxt 3" />
</template>
<script setup lang="ts">
import { filename } from 'pathe/utils';
const glob = import.meta.glob('~/assets/*.svg', { eager: true });
const images = Object.fromEntries(
Object.entries(glob).map(([key, value]) => [filename(key), value.default])
);
const dynamic_image_name = 'zero-config';
</script> |
Thanks @danielroe, this works like a charm! Do you think it makes sense to add the following helper method as a built-in composable? function useAsset(path: string): string {
const assets = import.meta.glob('~/assets/**/*', {
eager: true,
import: 'default',
})
// @ts-expect-error: wrong type info
return assets['/assets/' + path]
}
//Usage: <img :src="useAsset(dynamic_image_name + '.svg')" alt="Discover Nuxt 3" /> |
|
Is this the only way to get dynamic images in Nuxt 3? Was super easy in Nuxt 2 with require. |
+1 - I use the require() method to build 500 static pages using about 600 images which are inserted dynamically, a solution to this will be very much appreciated |
Wait for the official to provide a better solution.😅😅 |
Can someone explain this solution a little ? |
I think having some way to improve DX and fetch dynamic images easier would be helpful indeed |
The idea is to remove the filenames from the key so you don't have to write |
Also FYI, there is another caveat - when a |
Another way to do it is just use regular imports: <template>
<img :src="img.default" alt="Discover Nuxt 3" />
</template>
<script setup lang="ts">
const img = await import(`~/assets/${fileName}.svg`);
</script> |
i use this technique and it works with me just fine new URL(`../assets/images/${props.image}`,import.meta.url).href |
I created a temporary composable function while waiting for an official solution. It uses the above solution with good types as much as possible (I didn't succeed to have the correct import { filename } from "pathe/utils";
import { computed } from "#build/imports";
interface ImagesComposable {
getImageSrc: (fileName: string) => string | undefined;
}
function useImages(): ImagesComposable {
// TODO : replace the first parameter of the glob function according to your needs, I needed to import only png and jpeg from the images directory.
const images = computed(() => import.meta.glob("~/assets/images/*.(png|jpeg)", { eager: true }));
const getImageSrc = (fileName: string): string | undefined => {
for (const path in images.value) {
if (Object.hasOwn(images.value, path)) {
// unknown type is required here to change the final type as typescript thinks that images.value[path] is a function, it is not.
const image: unknown = images.value[path];
const imagePath = (image as { default: string }).default;
if (filename(imagePath) === filename(fileName)) {
return imagePath;
}
}
}
return undefined;
};
return { getImageSrc };
}
export { useImages };
// USAGE => const src = getImageSrc("test.png") |
I am also looking for something similar to require. In Nuxt 2 I used this to get the dimensions of an image, which was super useful: export default {
computed: {
imageDimensions() {
const image = require(`~/static/img/${this.src}`);
return {
width: image.width,
height: image.height,
}
},
},
} |
I managed to solve this by returning a new URL using a computed function. Store the path for your image in imagePath ref. <script setup>
const imgUrl = computed(() => {
return new URL(imagePath.value, import.meta.url).href;
});
</script>
<template>
<img :src="imgUrl" />
<template/> For more details check https://vitejs.dev/guide/assets.html#new-url-url-import-meta-url |
@sami-baadarani Thanks for providing the vite link for more details. Something to keep in mind with this approach: from the docs it states that:
|
The solution from @antoinezanardi worked well for me (thank you!) but only in dev. So to make it work in both dev and prod I had to change the condition from if (filename(imagePath) === filename(fileName)) to const regex = new RegExp('^' + filename(fileName) + '(?:\\.[a-zA-Z0-9]+)?$');
if (regex.test(filename(imagePath))) You have to be a bit careful if your filenames contain a period though, there is a chance it'll get mistakenly matched. |
This works for me. // ImageView.vue
<script setup lang="ts">
const props = defineProps<{
src: string;
alt: string;
}>();
function getImageUrl(path: string) {
const pathArr = path.split('.');
if (pathArr.length < 2) return undefined;
const url = `../assets/images${pathArr[0]}.${pathArr[1]}`; // change the path
return new URL(url, import.meta.url).href;
}
</script>
<template>
<img :src="getImageUrl(props.src)" :alt="props.alt" />
</template> Use like below: <ImageView
:src="`/carriers/${carrier}.svg`" // provide the path excluding initial
:alt="carrier"
class="h-6 w-6 flex-shrink-0 rounded-full"
/> |
For dynamic image use this
Note: define your directory properly, my image are saved in images folder. It work for me :) |
@Umer-Farooq10 this will break in prod |
I can't explain why, but this fn not working
and this one is working for me O_o :
|
I'd like to try out your code, but got stuck somehow.
This part has me stumped. When I try this all I get is an error like this:
Any thoughts on that @szulcus ? |
@IJsLauw |
is there any update on this? Anything official from the Nuxt team maybe? @danielroe? |
Also interested in how to address this. |
Is it fair to say that using Public folder is the best solution right now ? |
I solved it by using the following code:
For reference, in Nuxt 2 this component worked like this:
|
Sounds interesting. |
I am not sure to be honest... Maybe someone from the team can clarify this? |
If your files don't change in content, it is more performant (and a better decision, I think) to add them to the public folder. |
Finding it really frustrating to work with images, this needs to be properly addressed in the documentation: making it very clear that it is not possible to using images with dynamic names unless import.meta.glob is used. |
This is partially documented in the Vite guide, but I agree it should also be clarified in Nuxt docs. I also believe this is a Vite limitation, and the issue should be raised in vitejs/vite repository. Please correct me if I'm wrong. |
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
I've written a blog post about that topic recently, but the easiest way would be using the |
It is very sad, that the best solution for using dynamic assets with Vite is not to use dynamic assets. After years with Webpack, optimizing images by the bundler seems like a basic task, but not with Vite |
Yes, but the Vite team closes such issues since this limitation is "by design". You should have significant weight in the community to be heard by Vite team |
I have a set of country flag icons in my
It does work when running local, however, when running on prod, the images return a 404, here's the rendered element on prod: For images in the same I have no clue how to fix this, I can't be the only one with this problem. |
I assume there is no solution to this issue, even after attempting to use a new new URL(link, import.meta.url).href which only works locally but not in the production environment |
@joelee1992 There is, as Daniel pointed out in #14766 (comment) 😊 |
So the workaround is to move the files to the assets folder and use Daniels solution? |
@BorisKamp Well, you have two options (also explained here):
|
Thank you for your reply but that's the whole point: I am using the public folder, see my comment up here |
@BorisKamp Sorry, didn't see it was linked to the comment above. Do you have a minimal reproduction? Public folder should work in any case, no matter if referenced in the app or not 🤔 |
@manniL no problem man! Hmm do you know if I can reproduce a production environment locally? As my issue describes, this is only happening once deployed, with dynamic filename generation. I can verify that with static filename specification this does not happen. |
I think i just found an easy solution for this problem. I used Note
|
This one works like a charm (from https://www.lichter.io/articles/nuxt3-vue3-dynamic-images/ ):
|
Environment
Linux
v16.14.2
3.0.0-rc.8
npm@7.17.0
vite
-
-
-
Reproduction
https://stackblitz.com/edit/github-pq8nym?file=app.vue
Describe the bug
If you have an image referencing a dynamic asset, e.g.
then this is rendered as
without correctly resolving (and copying) the image, thus it doesn't show in the browser.
Additional context
Refs nuxt/framework#6635.
Logs
No response
The text was updated successfully, but these errors were encountered: