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 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 require in 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 }
}
2

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.

1

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>

demo

1

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>
1

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Robert Thorne

Robert Thorne

Automotive & Future Transportation Editor

Robert Thorne covers electric vehicle innovations, autonomous driving systems, global mobility trends, and automotive engineering developments.

Share this article
Twitter Facebook Pinterest