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:
Create desired image author-image.jpg
and put it in public
directory, created alongside app
directory.
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:
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:
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?
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.
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).*)']