vercel / next.js

The React Framework
https://nextjs.org
MIT License
126.68k stars 26.93k forks source link

next/image does not work with CDN #33488

Open gabor-at-reed opened 2 years ago

gabor-at-reed commented 2 years ago

Run next info (available from version 12.0.8 and up)

Operating System:
  Platform: win32
  Arch: x64
  Version: Windows 10 Pro
Binaries:
  Node: 16.13.0
  npm: 8.1.0
  Yarn: N/A
  pnpm: N/A
Relevant packages:
  next: 12.0.8
  react: 17.0.2
  react-dom: 17.0.2

What version of Next.js are you using?

12.0.8

What version of Node.js are you using?

16.3.0

What browser are you using?

Chrome

What operating system are you using?

Windows, Linux

How are you deploying your application?

Other platform

Describe the Bug

The issue relates to a previous bug, but that case was closed. However, I believe the issue still persists.

We have the CDN URL specified in the assetPrefix:

// next.config.js
module.exports = {
    assetPrefix: 'https://cdn.example.com'
}

Following the guide from the docs:

Files in the public folder; if you want to serve those assets over a CDN, you'll have to introduce the prefix yourself

In the code we have the following Image tag:

<Image
    src={`${assetPrefix}/images/cat.jpg`}
    alt="Cat"
    width={30}
    height={30}
/>

But the result in the markup is like this:

<img alt="Cat" src="/_next/image?url=https%3A%2F%2Fcdn.example.com%2Fimages%2Fcat.jpg&amp;w=64&amp;q=75" decoding="async" data-nimg="intrinsic" style="position:absolute;top:0;left:0;bottom:0;right:0;box-sizing:border-box;padding:0;border:none;margin:auto;display:block;width:0;height:0;min-width:100%;max-width:100%;min-height:100%;max-height:100%" srcset="/_next/image?url=https%3A%2F%2Fcdn.example.com%2Fimages%2Fcat.jpg&amp;w=32&amp;q=75 1x, /_next/image?url=https%3A%2F%2Fcdn.example.com%2Fimages%2Fcat.jpg&amp;w=64&amp;q=75 2x">

Expected Behavior

The expected behaviour should be that the initiator URL (src="/_next/image?url...) should also have the CDN prefix, like src="https://cdn.example.com/_next/image?url....

All compiled assets are loaded fine from the CDN by the way... so the _next folder is served from the CDN. That proves the assetPrefix setting is working properly, only the Image is failing.

To Reproduce

Use both <Image> and assetPrefix. Load image from the public folder.

gabor-at-reed commented 2 years ago

Any updates from Vercel's side on this?

andreisoare commented 2 years ago

Running into the same issue. This was reported here as well https://github.com/vercel/next.js/issues/20968 and it was never fixed. cc @ijjk since you were part of that conversation.

andreisoare commented 2 years ago

Looking at the Image component code it seems the default image loader uses the path property in next.config.js -> images. I was able to solve the author's issue with the following config:

images: {
  domains: [
    ...
  ],
  path: 'https://cdn.com/_next/image',
},

(fwiw I'm using Cloudflare CDN, but that shouldn't matter)

gabor-at-reed commented 2 years ago

@andreisoare, I'll try your suggested hack, but I don't think that should be the solution. Also, I have a strong feeling that we won't be able to use this path hack (even if it's working) for other reasons. I'll let you know next week how it goes. But as I said, the ultimate goal here is the assetPrefix should be fixed.

frahman5 commented 2 years ago

Hi I'm running into the same issue. @andreisoare I tried your hack. This is my next.config.js

module.exports = {
  assetPrefix: process.env.VERCEL_URL,
  images: {
    domains: [process.env.VERCEL_URL],
    path: `${process.env.VERCEL_URL}/_next/image`,
  },
};

FWIW the reason I'm using VERCEL_URL as the asset prefix is that my production site is living on a subdomain of another site. The site the client sees is isha.sadhguru.org. Then we setup a reverse proxy from isha.sadhguru.org/isha-yoga-center-california to the url of a Vercel website.

To get assets to load properly on the isha.sadhguru.org website, I need the URLs to be absolute paths to the underlying vercel URL, as relative paths would not get properly reverse-proxied back to the vercel URL.

Regardless, as far as the overall issue is concerned, I'm facing the same basic problem: NextJS Image does not work once I put an assetPrefix. And the path hack didn't seem to fix it.

Are there any other suggested hacks we can use while we wait for the vercel team to fix the underlying issue?

neeraj3029 commented 2 years ago

Creating a custom loader might help: https://nextjs.org/docs/api-reference/next/image#loader

dzcpy commented 2 years ago

Is it fixed?

ebameng commented 2 years ago

Is it fixed?

fabriciosautner commented 2 years ago

same problem

velidan commented 2 years ago

The same. I'm wondering about the modern JS ecosystem. Even the simple CDN image rendering might be an issue. So disappointing. P.S. The problem could be in the loader, I guess, because I played with the different loaders and in my case, the akamai was the problem somehow. I changed it to the default one and the images started to loading via the correct URL. Don't have any idea why. Here is my config:

  images: {
      domains: ['imagedelivery.net'],
    // loader: 'akamai',
    // assetPrefix: 'https://imagedelivery.net/'
  },

The problem in this solution that when I try to compile Next.js as the production static files, the default loader throws an error but Akamai does not. Weird. So need to play with it a bit more

ivstiv commented 2 years ago

We have a use case of more complex proxying where the initial page request is proxied to the next.js page running on a different domain. Fetching static assets with an assetPrefix afterwards is fine apart from optimised images. What @frahman5 and some of the others proposed with the "path" config entry solved our issue and the need for assetPrefix to apply to images. I am not sure if this was the intended use for the config entry though.

rzubrycki commented 1 year ago

any update on this one?

stefann01 commented 1 year ago

Any update here?

BohdanCredible commented 11 months ago

Any updates on the CDN issue?

chaudhry commented 9 months ago

Just override the Nextjs Image component as below and use this component instead of Next Image:

import NextImage from "next/image";

const Image = ({...props }: any) => {
    const imageLoader = ({src, width, quality}: any) => {
        return `${src}?w=${width}&q=${quality || 75}`
    }

    return (
        <NextImage loader={imageLoader}  {...props} />
    )
  }

export default Image;
SilvanTheuma commented 9 months ago

I believe I am having a similar issue. I have cloudflare DNS in front of my DO server. I am using remote images from firestorage and passing the src to next/image. If I build and start nextjs locally these work fine, however as soon as I deploy to my DO server, the images return a 400 coming from cloudflare with the error The requested resource is not a valid Image

I tried using the unoptimized flag on the next/image component and this renders the image fine, since it uses the firestorage url directly.

Has anyone experienced this issue?

t18n commented 4 months ago

Alternatively, you can set up custom loader via next.config.mjs file to use Image component directly. Example: https://github.com/t18n/next-cdn-image/blob/main/next.config.mjs#L3-L8

thinkingmonk commented 4 months ago

Any working solution for this ? As it works fine on localhost. On my docker setup the images throws 404 error PS: I tried copying next config to docker as well I am using assets.example.in to serve the images via cdn

      domains: ["assets.example.in","www.example.in"],
      minimumCacheTTL: 60,
      dangerouslyAllowSVG: true,
     remotePatterns: [
        {
          protocol: 'https',
          hostname: 'assets.example.in',
          port: '',
          pathname: '/**',
        },
        {
          protocol: 'https',
          hostname: 'www.example.in',
          port: '',
          pathname: '/**',
        },
      ]
thomas-noimos commented 2 months ago

No solution after 2 years ?