Safari loading issue with next/image and Sanity content lake URL

5 replies
Last updated: Oct 18, 2022
I’m having loading issues on Safari as there seems to be a problem with recognizing the source link to the sanity content lake (in production only, localhost works fine). Below is the
<img/>
rendered (by next/image), check src:Any idea what’s causing the loading problem here? Why doesn’t Safari get the served image as an image file?


<img
  alt="Alt 1"
  src="/_next/image?url=https%3A%2F%2Fcdn.sanity.io%2Fimages%2Febplvzey%2Fproduction%2F89d3576237a2b8840362eb811207e9d336137ed5-1200x630.jpg%3Fq%3D100&w=1920&q=100"
  decoding="async"
  data-nimg="responsive"
  style="position: absolute; inset: 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="100vw"
  srcset="/_next/image?url=https%3A%2F%2Fcdn.sanity.io%2Fimages%2Febplvzey%2Fproduction%2F89d3576237a2b8840362eb811207e9d336137ed5-1200x630.jpg%3Fq%3D100&w=360&q=100 360w,
  /_next/image?url=https%3A%2F%2Fcdn.sanity.io%2Fimages%2Febplvzey%2Fproduction%2F89d3576237a2b8840362eb811207e9d336137ed5-1200x630.jpg%3Fq%3D100&w=768&q=100 768w,
  /_next/image?url=https%3A%2F%2Fcdn.sanity.io%2Fimages%2Febplvzey%2Fproduction%2F89d3576237a2b8840362eb811207e9d336137ed5-1200x630.jpg%3Fq%3D100&w=1024&q=100 1024w,
  /_next/image?url=https%3A%2F%2Fcdn.sanity.io%2Fimages%2Febplvzey%2Fproduction%2F89d3576237a2b8840362eb811207e9d336137ed5-1200x630.jpg%3Fq%3D100&w=1440&q=100 1440w,
  /_next/image?url=https%3A%2F%2Fcdn.sanity.io%2Fimages%2Febplvzey%2Fproduction%2F89d3576237a2b8840362eb811207e9d336137ed5-1200x630.jpg%3Fq%3D100&w=1920&q=100 1920w"
>

Sep 12, 2022, 11:41 AM
Hello
user B
, must be frustrating!Could you share your nextJS component/page where the image appears in?
Is this issue only happening in Safari or in other browsers as well?
Is it only this one image or all images you load from sanity? Has there been any errors during build (and are you using SSR or SSG?)
Sep 12, 2022, 5:41 PM
Hi
user J
thank you for checking back on this!1. This issue is only occurring on Safari 15.6.1 (15613.3.9.1.16, 15613), Version 16.0 (17614.1.25.9.10, 17614) is working fine.
2. Happening with all images coming from Sanity via this component, and all using SSG (hosted on Netlify). A curious detail: for a brief moment on load the blur placeholder appears.
👀I created a custom component for dealign with images, which utilizes
next/image
and `@sanity/image-url`:
import React from 'react'
import Image from 'next/image'
import { inRange } from '../../lib/helpers'
import { urlFor } from '../../lib/sanity'

export default function Figure({ behavior, item }) {
  let media = {
    key: item?._key,
    type: item?._type,
    image: item?.image ?? item,
    video: item?.video ? {
      url: item?.video,
      caption: item?.caption
    } : {}
  }

  // Image
  const iWidth = media?.image?.asset?.metadata?.dimensions?.width
  const iHeight = media?.image?.asset?.metadata?.dimensions?.height

  // Crop
  const cWidth = Math.round(media?.image?.asset?.metadata?.dimensions?.width * (media?.image?.crop ? (1 - (media?.image?.crop?.left + media?.image?.crop?.right)) : 1))
  const cHeight = Math.round(media?.image?.asset?.metadata?.dimensions?.height * (media?.image?.crop ? (1 - (media?.image?.crop?.top + media?.image?.crop?.bottom)) : 1))
  const cX1 = Math.round(media?.image?.asset?.metadata?.dimensions?.width * (media?.image?.crop ? media?.image?.crop?.left : 0))
  const cX2 = cX1 + cWidth
  const cY1 = Math.round(media?.image?.asset?.metadata?.dimensions?.height * (media?.image?.crop ? media?.image?.crop?.top : 0))
  const cY2 = cY1 + cHeight

  // Hotspot
  const hIX = Math.round(media?.image?.hotspot?.x * iWidth)
  const hIY = Math.round(media?.image?.hotspot?.y * iHeight)
  const hCX = (hIX - cX1) / (cX2 - cX1)
  const hCY = (hIY - cY1) / (cY2 - cY1)

  return item ? (
    <figure>
      <div>
        <Image
          src={
            urlFor(media?.image)
              .rect(
                Math.round(media?.image?.asset?.metadata?.dimensions?.width * (media?.image?.crop ? media?.image?.crop?.left : 0)),
                Math.round(media?.image?.asset?.metadata?.dimensions?.height * (media?.image?.crop ? media?.image?.crop?.top : 0)),
                Math.round(media?.image?.asset?.metadata?.dimensions?.width * (media?.image?.crop ? (1 - (media?.image?.crop?.left + media?.image?.crop?.right)) : 1)),
                Math.round(media?.image?.asset?.metadata?.dimensions?.height * (media?.image?.crop ? (1 - (media?.image?.crop?.top + media?.image?.crop?.bottom)) : 1))
              )
              .quality(100)
              .url()
          }
          width={
            (behavior !== 'fill') && (
              media?.image?.crop ?
                (media?.image?.asset?.metadata?.dimensions?.width * (1 - (media?.image?.crop?.left + media?.image?.crop?.right))) :
                (media?.image?.asset?.metadata?.dimensions?.width)
            )
          }
          height={
            (behavior !== 'fill') && (
              media?.image?.crop ?
                (media?.image?.asset?.metadata?.dimensions?.height * (1 - (media?.image?.crop?.top + media?.image?.crop?.bottom))) :
                (media?.image?.asset?.metadata?.dimensions?.height)
            )
          }
          layout={behavior ?? 'responsive'}
          objectFit={behavior === 'fill' && 'cover'}
          objectPosition={
            (behavior === 'fill') && (
              media?.image?.hotspot ?
                (`
                  ${inRange(hCX, 0, (1/3)) ? 'left' : ''}
                  ${inRange(hCX, (1/3), (2/3)) ? 'center' : ''}
                  ${inRange(hCX, (2/3), 1) ? 'right' : ''}
                  ${inRange(hCY, 0, (1/3)) ? 'top' : ''}
                  ${inRange(hCY, (1/3), (2/3)) ? 'center' : ''}
                  ${inRange(hCY, (2/3), 1) ? 'bottom' : ''}
                `) : ('center center')
            )
          }
          quality={100}
          placeholder='blur'
          blurDataURL={media?.image?.asset?.metadata?.lqip ?? media?.image?.asset?.metadata?.palette?.dominant?.background}
          lazyBoundary='100px'
          alt={(media?.image?.alt ?? media?.image?.caption)}
        />
      </div>
    </figure>
  ) : null
}
Sep 30, 2022, 3:22 PM
Thats very curious indeed… that only one version of Safari is not working 🤔 Do you get any error messages in the console?

You put in a lot of work into the component, but did you know we have solutions for this built into the
urlForImage and a nextjs image plugin , that gives you a lot of options as well?
Oct 17, 2022, 12:36 PM
No error messages in the console, only a broken image with no content/information in the resources panel.
Yes I definitely cleaned up my code a lot since my original posting, integrated a couple of features from the resources you listed above. But I wanted to rebuild the logic first, just to understand it a bit better.
🤓
BUT looking into it again, I finally figured out the problem/solution: Nothing to do with sanity, all with the
next/image
component apparently “missing” a loader prop for it to properly render the returned URL string. 🤯

<Image
	loader={() => urlFor(media?.image).width(media?.image?.asset?.metadata?.dimensions?.width).url()}
	src={urlFor(media?.image).url()}
	…
/>
Thank you again for saving me from fading into despair!
🌻
Oct 18, 2022, 9:41 AM
Thank you again for saving me from fading into despair!
Please it was all you 🙂 But happy to be of service with any input 🌻
And impressive you were able to come this far without our tooling
:chefs-kiss:
Oct 18, 2022, 9:57 AM

Sanity– build remarkable experiences at scale

Sanity is a modern headless CMS that treats content as data to power your digital business. Free to get started, and pay-as-you-go on all plans.

Was this answer helpful?