
Mon Sep 25 2023
3 min read
Loading Images Dynamically in Vite and Vue 3
In this post, I'm walking through the process of dynamically loading images in a Vite and Vue 3 project. This is particularly useful when you want to change an image based on dynamic factors like props or reactive variables.
The Story
In Vue 2, it was common practice to use the require method for dynamically loading images. However, this approach no longer works seamlessly in Vue 3 with Vite.
Here's an example of how it was done in Vue 2:
Method 1
By inline import the image path.
<img :src="require(`~/assets/images/${src}`)" alt="..." />
Method 2
By storing the image path in a reactive variable in either data or props.
<!-- or store the image src in a reactive variable -->
<script>
export default {
data: {
imagePath: require(`~/assets/images/${this.src}`),
},
};
</script>
<template>
<img ref="imageRef" :src="imagePath" alt="..." />
</template>
Now, let's explore how to achieve the same in Vue 3 with Vite.
The Solution
When Server-Side Rendering (SSR) is Disabled
When SSR is disabled, we can resolve the imagePath to the correct bundled image path. Here's how to do it:
<script setup lang="ts">
const { src } = defineProps(['src']);
const imagePath = ref<string>();
imagePath.value = new URL(`../assets/images/${src}`, import.meta.url).href;
</script>
<template>
<img ref="imageRef" :src="imagePath" alt="..." />
</template>
This code uses the URL Javascript constructor that enable us to create and manipulate URLs (in our case the image
source url). And import.meta.url is a special javascript feature that allow access to the URL of current module (
component/script). And hence, allow us to get the relative path of the image relative to current component.
Here's a simple example to help you understand it better.
const relativeURL = new URL(url, base);
const relativeURL = new URL(
'/relative/path/to/resource',
'https://www.example.com',
);
NOTE: Path aliases like @ and ~ are not allowed in this case, so we have to use relative paths.
When Server-Side Rendering (SSR) is Enabled
When SSR is enabled, you might encounter an issue where the src attribute of an image doesn't get updated automatically after the Nuxt hydration step. To work around this, manually change the src attribute using the following code:
<script setup lang="ts">
const imagePath = ref<string>();
const imageRef = ref<HTMLImageElement>();
imagePath.value = new URL(path, import.meta.url).href;
if (imageRef.value && imagePath.value) {
imageRef.value.src = imagePath.value;
}
</script>
<template>
<img ref="imageRef" :src="imagePath" alt="..." />
</template>
These solutions ensure that your images load dynamically and correctly in both SSR-enabled and SSR-disabled scenarios.
Best Practice
Wrap this code inside a reusable function, useful when you want to build carousel slider or iterating on a list of
images using v-for.
<script setup lang="ts">
const getImageUrl = (src) => {
return new URL(`../assets/images/${src}`, import.meta.url).href;
};
</script>
<template>
<img ref="imageRef" :src="getImageUrl(src)" alt="..." />
</template>
References
For further details and documentation on handling assets in Vite, you can refer to the official Vite documentation:
https://vitejs.dev/guide/assets.html#new-url-url-import-meta-url