Frontend Development 12 min read

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.

Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Comprehensive Guide to Image Management in Vue 3 + Vite Projects

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.

frontendVuevitedynamic-importImage Management
Rare Earth Juejin Tech Community
Written by

Rare Earth Juejin Tech Community

Juejin, a tech community that helps developers grow.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.