Aljullu / react-lazy-load-image-component

React Component to lazy load images and components using a HOC to track window scroll position.
https://www.npmjs.com/package/react-lazy-load-image-component
MIT License
1.45k stars 110 forks source link

SSR, image not rendered from server #86

Open Gorbus opened 3 years ago

Gorbus commented 3 years ago

Bug description The lazy loading is working perfectly on client side but none of my image are rendered from the server on the original loading SSR. Is there a special config to change in order for the image to be rendered as SSR? Stack is Meteor/React/Apllo/Styled Component

<StyledLazyLoadImage
  alt={`product image ${name}`}
  scrollPosition={scrollPosition}
  src={imgUrl200 ? imgUrl200 : imgUrl}
/>
const StyledLazyLoadImage = styled(LazyLoadImage)`
  margin: 0.5rem;
  max-width: 18rem;
  max-height: 22rem;
`;

Also tried without the scrollPosition but result is the same.

Expected behavior Was expecting the image to be rendered on server side.

Screenshots image

Technical details:

foubei commented 3 years ago

Have you solved it?

jigar775 commented 3 years ago

Facing same issue.

petr-glaser-deltatre commented 2 years ago

I can confirm, this issue is still here. :/

petr-glaser-deltatre commented 2 years ago

Found the issue. The library is SSR friendly in a way it does not crash. So the flow on SSR with disabled JS is this:

Solution is to use placeholder={<img src={src} loading="lazy" />} which will keep the image rendered even on SSR with JS disabled.

ItsRyanWu commented 2 years ago

Found the issue. The library is SSR friendly in a way it does not crash. So the flow on SSR with disabled JS is this:

  • Start render on server
  • PlaceholderWithoutTracking is rendered and !supportsObserver is true
  • updateVisibility is called, but typeof window === 'undefined' is true, so false is returned
  • SSR renders placeholder, default placeholder is <span>

Solution is to use placeholder={<img src={src} loading="lazy" />} which will keep the image rendered even on SSR with JS disabled.

This way seems to be reasonable and workable and in the meantime we can still use placeholderSrc in parallel as the placeholderSrc will be used as a CSS background image property of the <span/> wrapper and the placeholder elements we explicitly set is a separate <img/> tag inside the wrapper. Btw a quick reminder that don't forget to set srcSet to the <img/> tag for the placeholder property if the original image is supposed to be assigned with it, otherwise your browser will waste network bandwidth to load unnecessary image files according to the src at first and then load the next correct resolution version according to the srcSet on the real <img/> tag after the website is mounted.

ItsRyanWu commented 2 years ago

Found the issue. The library is SSR friendly in a way it does not crash. So the flow on SSR with disabled JS is this:

  • Start render on server
  • PlaceholderWithoutTracking is rendered and !supportsObserver is true
  • updateVisibility is called, but typeof window === 'undefined' is true, so false is returned
  • SSR renders placeholder, default placeholder is <span>

Solution is to use placeholder={<img src={src} loading="lazy" />} which will keep the image rendered even on SSR with JS disabled.

I think an even better solution is we could wrap the <img/> inside the placeholder property with <noscript> tag, so it's will become only readable to the search engine and won't be executed by browsers in normal cases. I personally think it's a good way to improve performance when it's being parsed by browsers, as the placeholder is not really needed if you already set placeholderSrc property. So the final answer from me would be like this:

placeholder={
  <span>
    <noscript>
      {/* eslint-disable-next-line @next/next/no-img-element */}
      <img src={src} srcSet={srcSet} sizes={sizes} alt="placeholder" />
    </noscript>
  </span>
}

To be noticed that a <span/> or other non <noscript/> tags is required here to be a root node to prevent <LazyLoadImage/> from being failed to mount the real image element.