Vite / Vue 3: "Require Is Not Defined" When Using Image Source as Props
I Switched from the Vue Cli to Vite Cli, and from the Composition Api of Vue 3 to Sfc Script Setup Api. How It Previously Worked for Me When I Was Using the...
I switched from the Vue CLI to Vite CLI, and from the Composition API of Vue 3 to SFC Script setup API.
How it previously worked for me
When I was using the official Vue CLI, I could import an image source by passing the filename of the path by the props :
<template>
<img :src="require(`@/assets/${imagePath}`)"/>
<template/>
<script>
export default {
props: {
imagePath: { type: String },
},
setup() {
// ...
}
}
<script/>
And then call it like this :
<template>
<Image imagePath="icon.png" />
</template>
The error I get since I migrated to Vite
But since I migrated to the Vite CLI, I have an error "Uncaught ReferenceError: require is not defined". My file now use the script setup syntax and looks like this :
<script setup>
const props = defineProps({
imagePath: { type: String },
})
</script>
<template>
<img :src="require(`@/assets/${props.imagePath}`)"/>
</template>
What I tried
I already tried to import the file directly from the assets folder with a relative path, and it worked. But I cannot specify the path from props with the import statement.
<script setup>
// Works but do not use the props, so the component is not reusable
import logo from "./../assets/logo.png"
</script>
<template>
<img :src="logo"/>
</template>
<script setup>
// Component is reusable but the import statement has illegal argument I guess
const props = defineProps({
imagePath: { type: String },
})
import logo from `./../assets/${props.imagePath}`
</script>
<template>
<img :src="logo"/>
</template>
I also tried the import statement in the template but it cannot even compile the code :
<script setup>
const props = defineProps({
imagePath: { type: String },
})
</script>
<template>
<img :src="import `./../assets/${props.iconPath}`" />
</template>
Am I missing something ? Maybe a plugin exists and can help me achieve this ?
5 Answers
I also encountered this problem. I searched about this and found according to this github issue comment,
There should never be
requirein source code when using Vite. It's ESM only.
More about this on Features | Vite - Static Assets
A bit of searching lead me to this Vue 3 code sample link that worked for me
<CarouselItem v-for="(item,index) of carouselData" :key="index">
<img :src="getImageUrl(item.img_name)" />
</CarouselItem>
setup() {
const getImageUrl = (name) => {
return new URL(`../../lib/Carousel/assets/${name}`, import.meta.url).href
}
return { carouselData, getImageUrl }
}
In case you're using require.context, the new way seems to be glob import. Change your old statement from:
const locales = require.context("../../lang", true, /[A-Za-z0-9-_,\s]+\.json$/i)
to:
const locales = import.meta.glob('../../lang/*.json')
Edit:
This also seems to replace require.
Use a watcher on the imagePath prop that dynamically imports the image, and updates a ref (bound to the <img>.src) with the result:
<script setup>
import { ref, watchEffect } from 'vue'
const props = defineProps({
imagePath: { type: String },
})
const logo = ref()
watchEffect(async () => {
logo.value = (await import(/* @vite-ignore */ `../assets/${props.imagePath}`)).default
})
</script>
<template>
<img :src="logo">
</template>
for those who will use static assets with vue + vite, they can use this method.
import imgUrl from '../../img/bgimg.jpg'
export default {
data() {
return {
bgImage: imgUrl
};
},
};
then you can use it like this
<div class="ms-auto h-100 z-index-0 ms-n6"
:style="{
backgroundImage:
'url(' +
bgImage +
')',
}"
></div>
Importing a static asset will return the resolved public URL when it is served:
import imgUrl from './img.png'
document.getElementById('hero-img').src = imgUrl
For example, imgUrl will be /img.png during development, and become /assets/img.2d8efhg.png in the production build.
see also:
If none of provided answers is not help (as in my case) - try to use <slot/> instead, as shown below:
//card component (child)
<template>
<div class="card">
<slot />
</div>
</template>
//services component (parent)
<template>
<ServiceCard>
<img src="@/assets/icons/service-1.svg" alt="svg image" />
</ServiceCard>
<ServiceCard>
<img src="@/assets/icons/service-2.svg" alt="svg image" />
</ServiceCard>
</template>