twobin / react-lazyload

Lazy load your component, image or anything matters the performance.
MIT License
5.87k stars 488 forks source link

Support for search bots #109

Open oyeanuj opened 7 years ago

oyeanuj commented 7 years ago

Hi @jasonslyvia Thank you for putting out this library. Wondering if it supports showing the components to Google and other search engine bots, and/or if that is something you'd consider adding?

jasonslyvia commented 7 years ago

Do you mean using LazyLoad in Server Side Rendering situation?

oyeanuj commented 7 years ago

@jasonslyvia I meant showing the images or the components when being crawled by Google, etc, but that is similar to server-side rendering - how does it work to render the image/component then?

jasonslyvia commented 7 years ago

In SSR case, LazyLoad will render nothing.

oyeanuj commented 7 years ago

@jasonslyvia I think the search bot case is then different. In that case, you do want to have everything loaded and discoverable.

People tend use the logic specified here or here.

Thoughts?

andrepcg commented 7 years ago

I would also appreciate logic to return the children of <Lazyload> if it's being server-side rendered, instead of <div class="lazyload-placeholder"></div>

Redmega commented 7 years ago

What about pages where you want lazyloading for long lists of components but the page itself is server-side rendered? This wouldn't make sense in that regard, it would completely nullify any benefits of using the library

ptrwllrt commented 7 years ago

Currently in need of the same feature. I wonder if this could easily done with a prop to disable the lazy functionality? So everyone could apply their own rules on when to lazyload or not. It's basically: if (noLazy) { return this.props.children } But it should also not attach all events etc

I started taking the lib apart but go a bit lost. Any one up for the implementation? :)

jasonslyvia commented 7 years ago

@cainvommars If you can apply your logic in runtime, why not just:

render() {
  return (
    noLazy ? <Component /> : <LazyLoad><Component /></LazyLoad>
  );
}

So what you ask is basically just an option to implement aforementioned logic?

ptrwllrt commented 7 years ago

@jasonslyvia All good. This is what I've just build. I can totally work with that! Having a boolean to switch lazy on and off would just clean this up and might help others facing the same issue.

<LazyLoadOrChildren
  config={{once: true, offset: 200}}
  noLazyLoad={isThisAServer()}>
    <MyChildren />
</LazyLoadOrChildren>
import * as React from 'react';
import LazyLoad from 'react-lazyload';

function LazyLoadOrChildren(props: {
  config: {
    once?: boolean,
    height?: number,
    offset?: number | $ReadOnlyArray<number>
  },
  children: React.Node,
  noLazyLoad?: boolean
}) {
  if (props.noLazyLoad) {
    return props.children;
  }
  return <LazyLoad {...props.config}>{props.children}</LazyLoad>;
}

LazyLoadOrChildren.defaultProps = {
  config: {
    once: false,
    height: undefined,
    offset: 0
  },
  noLazyLoad: false
};
export default LazyLoadOrChildren;

Btw: Its a nice lib, I just threw it in and it does the job!

jasonslyvia commented 7 years ago

thanks, that's exactly what I expect this lib to do 😉

jf423 commented 7 years ago

@cainvommars How do you know isThisAServer ?

TikiCat7 commented 7 years ago

@jf423 One way to do it would be to use a webpack plugin to inject some type of is_Browser variable. https://webpack.js.org/plugins/banner-plugin/

webpack.config.client.js

    new webpack.BannerPlugin({
      banner: "__isBrowser__ = false;",
      raw: true,
      include: /\.js$/
    })

webpack.config.serverjs

    new webpack.BannerPlugin({
      banner: "__isBrowser__ = true;",
      raw: true,
      include: /\.js$/
    })
ptrwllrt commented 6 years ago

@jf423 My use case changed slightly. I'm now always render the first 30 photos in a grid and if the index is greater than 30 they get lazy loaded. So no need for the server side detection. - This works for me only because my users can will always start on the beginning of the photo grid.

oliviertassinari commented 6 years ago

Google is able to execute JS, but won't scroll the page. As soon as a non scrollable UA is detected (for example Opera mobile or google bot) all images are transformed instantly. This means google will not see the transparent image, but will probably index your data-src={src}.

For benchmarking consideration: lazysizes approach

IcanDivideBy0 commented 6 years ago
const img = <img src="/image.jpg" alt="" />;

return (
  <>
    <LazyLoad height={200}>{img}</LazyLoad>
    <noscript>
      <style>{`.lazyload-placeholder { display: none; }`}</style>
      {img}
    </noscript>
  </>
);

During server-side rendering, the placeholder will be placed along with the image in a noscript tag. Search engines will crawl images in noscript tag, while browsers won't load it (until LazyLoad replace the placeholder)!

Also the image will still be shown to users browsing your server-side rendered site with JS disabled!

If you’re using it a lot, consider putting the style tag once for all elsewhere in your document, but still inside a noscript.

jhoffmcd commented 5 years ago

@IcanDivideBy0 this was a better solution then checking server. It ensures our markup remains consistent on both client and server renders. Not sure if there is anything react-lazyload could do other then add this as default functionality. It is a major SEO concern.

abriginets commented 3 years ago

Not sure if this is still relevant to anyone but I would suggest adding enabled prop. For example, in Next.JS we have process.browser which is the boolean flag indicating if current environment is SSR or client-side. Using enabled prop we could easily match react hydration processes without mounting and unmounting components.