sealninja / react-grid-system

A powerful Bootstrap-like responsive grid system for React.
https://sealninja.github.io/react-grid-system/
MIT License
815 stars 83 forks source link

SSR - Unstyled / Wrong styled with Audit ? #162

Open sephi-dev opened 3 years ago

sephi-dev commented 3 years ago

Issues

Step to reproduce

What did I try

It's impacting the score of the audit.

Any idea ?

Here is some code :

// _app.tsx
setConfiguration({
    gridColumns: 12,
    defaultScreenClass: serverSideScreenClass,
    maxScreenClass: "xl",
    gutterWidth: 20,
  });

MyApp.getInitialProps = async (appContext: AppContext) => {
  const pageProps = App.getInitialProps ? await App.getInitialProps(appContext) : {};
  let userAgent: string;

  if (process.browser) {
    userAgent = navigator.userAgent;
  } else {
    userAgent = appContext.ctx.req.headers["user-agent"];
  }

  const md = new MobileDetect(userAgent);
  let serverSideScreenClass: string;
  if (md.phone() !== null) {
    serverSideScreenClass = "xs";
  } else if (md.tablet() !== null) {
    serverSideScreenClass = "md";
  } else {
    serverSideScreenClass = "xl";
  }

  return {
    ...pageProps,
    userAgent,
    serverSideScreenClass,
    namespacesRequired: ["common"],
  };
};
wanschi commented 3 years ago

Did you found a solution?

sephi-dev commented 3 years ago

Nop, I found à Way to improve but not that much..

sephi-dev commented 3 years ago

Ok, so I did a workaround.

With custom Next js server, I added with Mobile detect, the fallbackscreenclass in the headers, so I can initialize the grid with the fallback. But even with this hack, it's not working.

mattzque commented 3 years ago

Perhaps to clarify this a little bit for anyone stumbling over this or contemplates using this library, because I see you use lighthouse and I'm currently tasked with optimizing a site for the core web vitals that uses this library as well...

When we write modern web applications we want them to be responsive (for mobile/tablet/desktop/toasters), the web has a solution for this for many years in CSS called media-queries:

@media (min-width: 577px) {
    ... tablet styling go here ...
}

When you use a modern framework like mui and use their Grid components you would write something like:

<Grid item xs={6}>
    ...
</Grid>

In the background this generates CSS with media queries using CSS-in-js (just pseudocode):

@media (max-width: 577px) {
.<generated-class-name> {
  width: 50%;
}
}

This is what a library like react-grid-system should do.

Instead this library takes a fundamentally different approach, it uses JavaScript to determine the viewport width, then its Grid/Col components change the inline-style attribute depending on the screen size. Its emulating media-queries in javascript/react.

When we attempt to render the page on the server all the CSS will be generated for some screen size, the client renders the page (HTML and CSS first, before JavaScript) in whatever the screen size the library thought it was during the server side render. Once the javascript is loaded and executed and the real device screen size is determined, this library then has to change all the CSS again and the browser does a repaint of all the elements effected by the change. During all of which the user can't interact with the page.

You will never know the exact screen size / window size in advance of rendering the page on the server.

The Core Web Vitals (which now also effect Google ranking) take heavy emphasis on time to first paint metrics and first to interactive, this library - by design - makes optimizing those metrics impossible.

sephi-dev commented 3 years ago

I found the issue on my side. I removed the setConfiguration which was too slow to initialize. I kept only what I wanted from the lib and the issue was gone. Keep it light :)