javascriptnuxt.jsassetsvitenuxt3.js

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?


Solution

  • 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.