Comprehensive Guide to Image Management in Vue 3 + Vite Projects
This article explains how to organize, import, dynamically load, batch import, and lazily load images in Vue 3 + Vite applications, covering static assets, CSS references, template usage, URL handling, import.meta.glob, and common pitfalls with path aliases.
In Vue 3 + Vite projects, managing images efficiently improves performance and developer experience. Images are typically stored in two directories: src/assets for assets that need Vite processing (supporting dynamic imports and alias @ ) and public for static resources that are served directly.
Static Image Loading
Template Import from src/assets
<template>
<img src="@/assets/a.jpg" alt="Static Image" />
</template>Template Import from public
<template>
<img src="/vite.svg" alt="Public Image" />
</template>Relative Path Import
<template>
<img src="../assets/b.jpg" alt="Relative Image" />
</template>CSS Background Image
.background {
background-image: url('@/assets/a.jpg');
} .background {
background-image: url('/vite.svg');
} .background {
background-image: url('../assets/b.jpg');
}Dynamic Image Loading
Why Use Dynamic Loading
Dynamic loading is needed when image paths are generated from data at runtime.
<template>
<div class="wrap">
<img :src="imagePath" />
</div>
</template>
<script setup>
import { ref } from 'vue'
const name = "c.jpg"
const imagePath = `@/assets/${name}`
</script>This approach fails because the @ alias is not resolved inside template strings. The alias works only with import statements or Vite’s dynamic import APIs.
Using new URL (no variables)
<template>
<img :src="imagePath" alt="Static Image" />
</template>
<script setup>
const imagePath = new URL('@/assets/c.jpg', import.meta.url).href;
console.log(imagePath);
</script>Variables cannot be used directly with new URL because the alias is resolved only at build time.
Dynamic Loading with Variables
Several alternatives exist:
Use a relative path: const name = "c.jpg"; const imagePath = new URL(`../assets/${name}`, import.meta.url).href;
Use import.meta.glob for batch imports: const images = import.meta.glob('@/assets/*.jpg', { eager: true }); const name = "c.jpg"; const imagePath = images[`/src/assets/${name}`]?.default;
Avoid the alias and build the path manually: const name = "c.jpg"; const imagePath = new URL(`src/assets/${name}`, import.meta.url).href;
Looping Over Images
When iterating with v-for , the alias is treated as a plain string and does not resolve:
<template>
<div v-for="name in imageNames" :key="name">
<img :src="getImagePath(name)" :alt="name" />
</div>
</template>
<script setup>
const imageNames = ['b.jpg', 'c.jpg', 'd.jpg'];
const getImagePath = (fileName) => {
return new URL(`@/assets/${fileName}`, import.meta.url).href;
};
</script>Solutions include using relative paths, placing images in public , or pre‑building an array of resolved URLs.
Batch Dynamic Import with import.meta.glob
import.meta.glob scans a directory and returns a mapping of file paths to import functions (or the imported module when eager: true is set).
const images = import.meta.glob('@/assets/*.jpg', { eager: true });
for (const [key, value] of Object.entries(images)) {
const fileName = key.split('/').pop();
// value.default contains the image URL
}Advanced usage can filter files with patterns, e.g., gcshi_*.jpg :
const imageFiles = import.meta.glob('@/assets/images/gcshi_*.jpg');Lazy Loading Images
To improve first‑paint performance, integrate a lazy‑load library such as vanilla‑lazyload :
<template>
<div v-for="(src, name) in images" :key="name" class="image-container">
<img :data-src="src" :alt="name" class="lazy" />
</div>
</template>
<script setup>
import LazyLoad from 'vanilla-lazyload';
const imageFiles = import.meta.glob('@/assets/images/*.jpg');
const images = {};
for (const [key, value] of Object.entries(imageFiles)) {
images[key.split('/').pop()] = await value();
}
onMounted(() => {
new LazyLoad({ elements_selector: '.lazy' });
});
</script>Common Issues and Fixes
Path Alias Not Working
Ensure the alias is correctly defined in vite.config.js :
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import { resolve } from 'path';
export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
"@": resolve(__dirname, "src"), // maps @ to src directory
},
},
});Incorrect CSS Paths After Build
Use absolute paths referencing the public folder or Vite’s alias for assets located in src/assets .
Conclusion
By applying the techniques above—static imports, new URL for dynamic paths, import.meta.glob for batch imports, and lazy‑load integration—developers can manage images in Vue 3 + Vite projects more efficiently and reliably.
Rare Earth Juejin Tech Community
Juejin, a tech community that helps developers grow.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.