Toni Michel Caubet
Toni Michel Caubet

Reputation: 20163

Why loading dynamically assets fails on Nuxt v3

I'm experience a weird situation,

I have a "standard" Nuxt v3 project that comes with vite

Works

<img src="~/assets/img/image.png">
<img src="~/assets/video/video.mp4">

Does not work

<img :src="require('~/assets/img/image.png')">
<img :src="require('~/assets/video/video.mp4')">

Note that the image path is the same so it does exist, the error I'm getting is:

Cannot find module '@/assets/img/image.png' Require stack

The docs don't mention anything that has to be done in order to achieve it

enter image description here

Is there anything I should do?

Upvotes: 11

Views: 5725

Answers (1)

sadeq shahmoradi
sadeq shahmoradi

Reputation: 2365

Updated

If you want to dynamically import images use this function

export const useDynamicImage = async (path) => {
  const images = import.meta.glob("/src/assets/images/**/*");
  const image = (await images[path.replace("@", "/src")]()).default;

  return image as string;
};

this function will return the correct converted path by vite and its works perfectly after build

Old answser

In Vite, the require function is not used; instead, you should utilize the import statement (Vite is the default module bundler for Nuxt 3).

Two main issues exist:

  1. Vite alters the assets directory and file names after the build.
  2. Aliases do not convert to absolute paths when used dynamically.

For example, the following won't work:

<img :src="`_nuxt/assets/img/${imageName}`">

It works during development mode, but not after the build

Solution 1

I found this method:

export const useDynamicImage = (path: string): string =>
    new URL(path, import.meta.url).toString();

Add this to your compostables. You can pass your path to this function and retrieve the absolute path. This approach continues to function correctly even after the build.

use /src not @/

Solution 2

I found this way:

<script>
const glob = import.meta.glob("~/assets/images/how-to-use/*", {
  eager: true,
});

const getImageAbsolutePath = (imageName: string): string => {
  return glob[`/assets/images/how-to-use/${imageName}`]["default"];
};
</script>

You can pass your imageName (don't forget the extension) to this function and retrieve the absolute path.

This approach continues to function correctly even after the build.

Solution 3

Import images and use them like this:

<script lang="ts" setup>
//@ts-ignore
import image1 from "../assets/images/image1.jpg";
//@ts-ignore
import image2 from "../assets/images/image2.jpg";
//@ts-ignore
import image3 from "../assets/images/image3.jpg";

const images = [image1, image2, image3];
</script>

Solution 4

Place your images in the public directory.

Learn more: Nuxt Docs - Public Directory

The public/ directory content is served at the server root as-is.

Upvotes: 21

Related Questions