react-lazy-load-image-component
react-lazy-load-image-component copied to clipboard
SSR, image not rendered from server
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
Technical details:
- Package version: 1.5.1
- Server Side Rendering? Yes
- Device: Desktop
- Operating System: MacOs
- Browser: Chrome
Have you solved it?
Facing same issue.
I can confirm, this issue is still here. :/
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, buttypeof window === 'undefined'
is true, sofalse
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.
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 trueupdateVisibility
is called, buttypeof window === 'undefined'
is true, sofalse
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.
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 trueupdateVisibility
is called, buttypeof window === 'undefined'
is true, sofalse
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.