Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Next/Image] Images on Safari are getting downloaded multiple times in different sizes #19478

Closed
Elia-Darwish opened this issue Nov 24, 2020 · 7 comments · Fixed by #22902
Closed
Assignees
Milestone

Comments

@Elia-Darwish
Copy link

Elia-Darwish commented Nov 24, 2020

Bug report

Describe the bug

The image component is only requesting the image in the original size on safari for some reason, the requested Url always looks like this http://localhost:3000/_next/image?url=%2Fitalian-fabric-dark-blue.jpg&w=3840&q=75.

Code:

export default function Home() {
  return (
    <div className="max-w-screen p-16">
      <Head>
        <title>Create Next App</title>
        <link rel="icon" href="/favicon.ico" />
      </Head>

      <main className="max-w-full max-h-full">
        <div className="relative">
          <Image
            src="/italian-fabric-dark-blue.jpg"
            width={3984}
            height={2656}
            alt=""
          />
        </div>
      </main>
    </div>
  )
}

html output:

<main class="max-w-full max-h-full">
  <div class="relative">
    <div
      style="
        display: inline-block;
        max-width: 100%;
        overflow: hidden;
        position: relative;
        box-sizing: border-box;
        margin: 0;
      "
    >
      <div style="box-sizing: border-box; display: block; max-width: 100%">
        <img
          style="max-width: 100%; display: block"
          alt=""
          aria-hidden="true"
          role="presentation"
          src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMzk4NCIgaGVpZ2h0PSIyNjU2IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZlcnNpb249IjEuMSIvPg=="
        />
      </div>
      <img
        alt=""
        src="/_next/image?url=%2Fitalian-fabric-dark-blue.jpg&amp;w=3840&amp;q=75"
        decoding="async"
        style="
          visibility: visible;
          position: absolute;
          top: 0px;
          left: 0px;
          bottom: 0px;
          right: 0px;
          box-sizing: border-box;
          padding: 0px;
          border: none;
          margin: auto;
          display: block;
          width: 0px;
          height: 0px;
          min-width: 100%;
          max-width: 100%;
          min-height: 100%;
          max-height: 100%;
        "
        srcset="
          /_next/image?url=%2Fitalian-fabric-dark-blue.jpg&amp;w=3840&amp;q=75 1x
        "
      />
    </div>
  </div>
</main>

and when adding the sizes attributes two images are requested at the same time http://localhost:3000/_next/image?url=%2Fitalian-fabric-dark-blue.jpg&w=3840&q=75 and http://localhost:3000/_next/image?url=%2Fitalian-fabric-dark-blue.jpg&w=640&q=75

code:

export default function Home() {
  return (
    <div className="max-w-screen p-16">
      <Head>
        <title>Create Next App</title>
        <link rel="icon" href="/favicon.ico" />
      </Head>

      <main className="max-w-full max-h-full">
        <div className="relative">
          <Image
            src="/italian-fabric-dark-blue.jpg"
            width={3984}
            height={2656}
            sizes="50vw"
            alt=""
          />
        </div>
      </main>
    </div>
  )
}

output

<main class="max-w-full max-h-full">
  <div class="relative">
    <div
      style="
        display: block;
        overflow: hidden;
        position: relative;
        box-sizing: border-box;
        margin: 0;
      "
    >
      <div
        style="
          display: block;
          box-sizing: border-box;
          padding-top: 66.66666666666666%;
        "
      ></div>
      <img
        alt=""
        src="/_next/image?url=%2Fitalian-fabric-dark-blue.jpg&amp;w=3840&amp;q=75"
        decoding="async"
        style="
          visibility: visible;
          position: absolute;
          top: 0px;
          left: 0px;
          bottom: 0px;
          right: 0px;
          box-sizing: border-box;
          padding: 0px;
          border: none;
          margin: auto;
          display: block;
          width: 0px;
          height: 0px;
          min-width: 100%;
          max-width: 100%;
          min-height: 100%;
          max-height: 100%;
        "
        sizes="50vw"
        srcset="
          /_next/image?url=%2Fitalian-fabric-dark-blue.jpg&amp;w=640&amp;q=75   640w,
          /_next/image?url=%2Fitalian-fabric-dark-blue.jpg&amp;w=750&amp;q=75   750w,
          /_next/image?url=%2Fitalian-fabric-dark-blue.jpg&amp;w=828&amp;q=75   828w,
          /_next/image?url=%2Fitalian-fabric-dark-blue.jpg&amp;w=1080&amp;q=75 1080w,
          /_next/image?url=%2Fitalian-fabric-dark-blue.jpg&amp;w=1200&amp;q=75 1200w,
          /_next/image?url=%2Fitalian-fabric-dark-blue.jpg&amp;w=1920&amp;q=75 1920w,
          /_next/image?url=%2Fitalian-fabric-dark-blue.jpg&amp;w=2048&amp;q=75 2048w,
          /_next/image?url=%2Fitalian-fabric-dark-blue.jpg&amp;w=3840&amp;q=75 3840w
        "
      />
    </div>
  </div>
</main>

Our production server is also crashing every time it is visited from a Safari browser (seems to happen more on iOS) and this error is logged

Killed
error Command failed with exit code 137.

To Reproduce

here is a minimal codeSandbox.

  1. open the sandbox in Safari
  2. open network tab
  3. notice the image is loaded in the original size
  4. add the sizes attribute the Image component
  5. notice the image loaded twice in the network tab

Expected behaviour

The Image component should load the correct image like in other browsers

System information

  • OS: macOS 11.0.1
  • Browser Safari
  • Version of Next.js: 10.0.3
  • Version of Node.js: 14.15.0
  • Deployment: next start

Additional context

Add any other context about the problem here.

@Elia-Darwish Elia-Darwish added the bug Issue was opened via the bug report template. label Nov 24, 2020
@Elia-Darwish
Copy link
Author

I've been testing around and I've noticed a couple of things, of course all of this is only happening (in my case) in Safari.

first, the behaviour differs from one layout mode to another. for example, setting the layout prop to fill or responsive is causing the same image to be downloaded three times or sometimes more. but only the correct image size is shown in the image tag.

often this error is showing in the console

[Error: ENOENT: no such file or directory, unlink '/Users/elia/Desktop/playground/next-image/.next/cache/images/9G8LlgjhcAHaytCnfziyTyUqLsNnv7Z5zXhyNBUSJGw=/1606475905162.vSeS9FT7kbvQQwhM0jGQCyFkfczi+MxKPZHeoZNnkfQ=.webp'] {
  errno: -2,
  code: 'ENOENT',
  syscall: 'unlink',
  path: '/Users/elia/Desktop/playground/next-image/.next/cache/images/9G8LlgjhcAHaytCnfziyTyUqLsNnv7Z5zXhyNBUSJGw=/1606475905162.vSeS9FT7kbvQQwhM0jGQCyFkfczi+MxKPZHeoZNnkfQ=.webp'
}

setting the loading prop to eager seemed to solve the problem in all the test cases I have been playing around with, but not in the production code though!

Thank you very much for the time and effort 🙏

@Elia-Darwish Elia-Darwish changed the title [Next/Image] Images on Safari are always loaded in original size and are loaded twice when using sizes [Next/Image] Images on Safari are getting downloaded multiple times in different sizes Nov 27, 2020
@ericvrp
Copy link

ericvrp commented Dec 22, 2020

I am facing similar error messages and in this case no image is shown in the frontend. For me it happens on multiple browsers (Brave on iPadOS and Chrome and Firefox on Windows) and in develop-mode but most of all in a semi-busy production site hosted on Azure.

[Error: ENOENT: no such file or directory, unlink '/Users/elia/Desktop/playground/next-image/.next/cache/images/9G8LlgjhcAHaytCnfziyTyUqLsNnv7Z5zXhyNBUSJGw=/1606475905162.vSeS9FT7kbvQQwhM0jGQCyFkfczi+MxKPZHeoZNnkfQ=.webp'] {
  errno: -2,
  code: 'ENOENT',
  syscall: 'unlink',
  path: '/Users/elia/Desktop/playground/next-image/.next/cache/images/9G8LlgjhcAHaytCnfziyTyUqLsNnv7Z5zXhyNBUSJGw=/1606475905162.vSeS9FT7kbvQQwhM0jGQCyFkfczi+MxKPZHeoZNnkfQ=.webp'
}

@joshourisman
Copy link

I am seeing this issue as well, also with no image being shown on the frontend as in @ericvrp's case. In my case I am getting a broken image in Safari 14.0.2 on macOS (11.1), as well as Safari on iPadOS, but the image displays in Safari on iOS as well as Firefox (83.0) on macOS.

[Error: ENOENT: no such file or directory, unlink '/workspaces/pingpong.travel/.next/cache/images/SSDihwa5Rpid9WOaqGHXieWcPjQ6g2nmnDshXVzX3go=/1608666754323.MI1ZB4n+pBxN1kBxzEgjaVzIn06EztpKwvpNVKl0jy0=.webp'] {
  errno: -2,
  code: 'ENOENT',
  syscall: 'unlink',
  path: '/workspaces/pingpong.travel/.next/cache/images/SSDihwa5Rpid9WOaqGHXieWcPjQ6g2nmnDshXVzX3go=/1608666754323.MI1ZB4n+pBxN1kBxzEgjaVzIn06EztpKwvpNVKl0jy0=.webp'
}

@ericvrp
Copy link

ericvrp commented Dec 22, 2020

It might be another version (resolution/format) of the image that you are seeing.

@Timer Timer added kind: bug and removed bug Issue was opened via the bug report template. labels Jan 8, 2021
@Timer Timer added this to the iteration 16 milestone Jan 8, 2021
@rmhowe
Copy link

rmhowe commented Feb 3, 2021

We're also running into this issue with Safari on macos. Requests to the next server when using next/image cause the image resizing process to fail on the first request and so images are not displayed, but subsequent requests seem to succeed. Seen on Safari 13.1.2 on macos 10.13.6 and Safari 14.0.3 on macos 11.2. Next.js 10.0.5 node 10.15.3

@bryanMeneses
Copy link

I am using Next.js 10.0.5 too and all my images that are using next/image are getting downloaded three times in Safari. Any idea how to fix this?

@shuding shuding self-assigned this Mar 8, 2021
@kodiakhq kodiakhq bot closed this as completed in #22902 Mar 9, 2021
kodiakhq bot pushed a commit that referenced this issue Mar 9, 2021
Currently if you have `sizes` set in `next/image`, the image will likely be downloaded multiple times (usually twice) on Safari (macOS and iOS): the correct size for the viewport, and the original size specified in `src`. 

Also make sure you have "Ignore Resource Cache" disabled in the Safari Devtools when trying to reproduce:

![CleanShot 2021-03-09 at 21 05 54@2x](https://user-images.githubusercontent.com/3676859/110476820-6399f180-811d-11eb-93ec-5b2482c87884.png)

The root cause is the way Safari handles `<img>`'s attribute updates. Although React updates all the attributes one by one synchronously and programmatically, Safari will still try to fetch the resource immediately and won't wait for other DOM changes to be finished. 

That means if we set the following 3 attributes in this order: `src`, `srcSet`, `sizes`. Safari will fetch the image when `src` is set. And then once `srcSet` is there it will fetch the resource again based on it. And finally, when `sizes` is updated it might correct the resource URL again.

So the fix here is simple: by just reordering those to `sizes`, `srcSet`, `src`, it will only load the image with the correct size only once:

<img width="1498" alt="CleanShot 2021-03-09 at 21 05 30@2x" src="https://user-images.githubusercontent.com/3676859/110477852-a27c7700-811e-11eb-88dc-d6e7895f67bd.png">

Fixes #19478.
@balazsorban44
Copy link
Member

This issue has been automatically locked due to no recent activity. If you are running into a similar issue, please create a new issue with the steps to reproduce. Thank you.

@vercel vercel locked as resolved and limited conversation to collaborators Jan 28, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

9 participants