reactjsnext.jsnextjs-image

Next.js - Image component loading issue


I have completed basic course on Next.js, where I used Image component in the following way:

<Image
    src="/hero-desktop.png"
    width={1000}
    height={760}
    className="hidden md:block"
    alt="Screenshots of the dashboard project showing desktop version"
></Image>

and hero-desktop.png was in the public directory, alongside app directory with all the routes.

This worked seamlessly.

Now, in other Next.js project I want to use the same (in order to get optimized handling of images), so I have followed the same steps:

  1. Create desired image author-image.jpg and put it in public directory, created alongside app directory.

  2. Add following code:

<Image
  src="/author-image.jpg"
  width={200}
  height={200}
  alt="Michał Turczyn"
  loading="eager"
></Image>

After this setup, I get only Bad Request response for request to get the image:

enter image description here

I also have tried other solution: try to import the image and set src property to that imported value:

import authorImage from '/author-image.jpg';

and

<Image
    src={authorImage}
    width={200}
    height={200}
    alt="Michał Turczyn"
    loading="eager"
></Image>

Also have tried

import authorImage from 'author-image.jpg';

Both attempts resulted in error: enter image description here

Also I've put loading='eager' to override default value loading='lazy' from Next.js. It has no effect on behavior in question.

How could I load the image correctly? Why this issue is happening?


Solution

  • Root cause

    I was also working with internationalization, which influenced routing in Next.js (detecting language from route, redirecting to fallback locale, etc.). So I had custom middleware, for which I used standard pattern for matcher:

    export const config = {
      // Matcher ignoring /_next/ and /api/
      matcher: ['/((?!api|_next/static|_next/image|favicon.ico).*)'],
    };
    

    Which handles routes, except for Next.js specific routes.

    When I speicifed src="/author-image.jpg", it was matched by my middleware matcher and caused problems.

    On the other hand, when I specified

    import authorImage from '../../public/author-image.jpg';
    

    Next.js recognized this import and optimized and produced appropriate files in its own directory (optimized image by producing different file formats and sizes), which falls under "Next.js specific" routing, which is not influenced by my middleware matcher, thus working correctly.

    So the main reason was my custom middleware in Next.js.

    Original answer

    So I have followed this tutorial Image Optimization, and there, the reference to image was done differently, so in my example I needed to add such import statement:

    import authorImage from '../../public/author-image.jpg';
    

    Turns out I needed to specify relative path for the image file.

    As specified in linked article, it also enables Next.js to provide values for width and height, so they become optional in Image component.

    Then specifying src={authorImage} worked as expected.

    NOTE: As it turned out, I was using Next in different version "next": "14.0.1" (here I had to import via relative path), while in my tutorial project I have used "next": "^14.0.2" (entires come from package.json).

    UPDATE

    Approach with importing via relative path works also in "next": "14.1.1". As I also work with internationalization, I have modified routing in my app. It breaks Image sources, when specified as path relative to root.

    But when specified as import via relative path, it works great, as routing for the image falls under Next.js routing, which I have handled once and for all in my custom middleware (to enhance and enable language detection in URL), by using default matcher from all Next.js middleware examples:

    matcher: ['/((?!api|_next/static|_next/image|assets|favicon.ico|sw.js).*)']