Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Server-side-rendered styles are missing and/or incorrect #17676

Closed
SMerdzhanov opened this issue Sep 16, 2019 · 31 comments
Closed

Server-side-rendered styles are missing and/or incorrect #17676

SMerdzhanov opened this issue Sep 16, 2019 · 31 comments
Labels
type: bug An issue or pull request relating to a bug in Gatsby

Comments

@SMerdzhanov
Copy link

Description

I've built multiple sites/apps with Gatsby already, but that's the first time I encounter such an issue.

I'm working on an app based on Gatsby and Material UI.

GitHub issues reporting similar, but not the same behavior that I reviewed and tested #9911, #12360, #5100, #3741.

GIF/recording of the issue https://monosnap.com/file/gQ7jH0YQ4O39LpHhL8DOL40eufnbbY

Sometimes, on initial page load (server-side-rendered per my understanding) the styles get totally messed up. This does not happen on subsequent (client-side) rendered pages, but only on the initial page load. Unfortunately, it occurs randomly and not on every build.

Setup
The setup of Gatsby and Material UI is based on MUI's official Gatsby example.
In short, gatsby-plugin-material-ui and changes to gatsby-browser.js and gatsby-ssr.js

This very same setup, as described in the GH project itself, works perfectly fine on other projects. Therefore, I speculate there's something that we're missing.

  • We do not use styled-components or any similar CSS-in-JS library and such doesn't exist in package.json
  • The only .css files we have are placed at the top of gatsby-browser.js like this
import 'slick-carousel/slick/slick-theme.css';
import 'slick-carousel/slick/slick.css';
import '~components/bar-bat-mitzvah/raleway-font.css';
  • I tested using the gatsby-plugin-material-ui's option for injectFirst as described here, but without any success.
  • Clearing all "Site Data" from the Developer Tools console seems to fix the issue which might be a hint to something wrong with cached styles by the gatsby-plugin-offline
  • In addition, I tested many of the solutions in the mentioned GH issues, but none of these worked.

Steps to reproduce

Unfortunately, I can't grant access to the project's repository. I have the very same project setup as GH repository that I'm sharing for reference.

  • Developing and browsing the app locally using gatsby develop works perfectly fine.
  • Building using gatsby build passes just fine too. No warnings or errors.
  • Serving using gatsby serve serves the already built files. However, styles get messed up as described in this issue.

Expected result

It's expected to load any styles properly on both initial and subsequent renders.

Actual result

The styles on initial-render get messed up and/or are corrupted. Please check the video recording at the top of the issue.

Environment

# gatsby info --clipboard
  System:
    OS: macOS 10.14.6
    CPU: (8) x64 Intel(R) Core(TM) i7-6700HQ CPU @ 2.60GHz
    Shell: 3.2.57 - /bin/bash
  Binaries:
    Node: 10.16.0 - ~/.nvm/versions/node/v10.16.0/bin/node
    Yarn: 1.13.0 - ~/.yarn/bin/yarn
    npm: 6.9.0 - ~/.nvm/versions/node/v10.16.0/bin/npm
  Languages:
    Python: 2.7.13 - /usr/local/bin/python
  Browsers:
    Chrome: 76.0.3809.132
    Firefox: 68.0.1
    Safari: 12.1.2
  npmPackages:
    gatsby: ^2.13.11 => 2.15.14 
    gatsby-plugin-create-client-paths: ^2.1.3 => 2.1.7 
    gatsby-plugin-facebook-pixel: ^1.0.3 => 1.0.3 
    gatsby-plugin-google-analytics: ^2.0.6 => 2.1.16 
    gatsby-plugin-mailchimp: ^5.1.0 => 5.1.2 
    gatsby-plugin-manifest: ^2.0.4 => 2.2.16 
    gatsby-plugin-material-ui: ^2.0.1 => 2.1.6 
    gatsby-plugin-nprogress: ^2.1.0 => 2.1.6 
    gatsby-plugin-offline: ^2.0.5 => 2.2.10 
    gatsby-plugin-react-helmet: ^3.0.0 => 3.1.7 
    gatsby-plugin-robots-txt: ^1.3.0 => 1.5.0 
    gatsby-plugin-root-import: ^2.0.5 => 2.0.5 
    gatsby-plugin-s3: 0.3.1 => 0.3.1 
    gatsby-plugin-sitemap: ^2.0.1 => 2.2.12 
    gatsby-plugin-webpack-size: 1.0.0 => 1.0.0 
    gatsby-source-prismic: 2.3.0-alpha.6 => 2.3.0-alpha.6 

Thank you for spending the time to look into this!

@LekoArts LekoArts added the type: bug An issue or pull request relating to a bug in Gatsby label Sep 17, 2019
@LekoArts
Copy link
Contributor

So to get on the same page here: This reproduces the issue you are seeing on your page?
https://github.com/mkitio/mkit-bundle-gatsby

@SMerdzhanov
Copy link
Author

SMerdzhanov commented Sep 17, 2019

Hey @LekoArts, no. I think my comment confused you.

I can't share the actual code repository where the issue is occurring. Here's a link to the deployed web-app where we see the issues happening.

This mkit-bundle-gatsby repo is actually a starter project I used. It's linked here as demo of the Gatsby + MUI setup that I have. And it's working completely fine.

So I'm trying to understand what else could have gone wrong because the setup itself seems to be working fine. If it's going to be helpful I can share some snippets of the source code?


Update

I had a gut feeling that the gatsby-plugin-offline is messing up the styles. I removed it, cleared my browser's "Site Data".

I'm testing the app built by gatsby build at the moment, but so far it seems that the issue is gone.

If that's the case, then we can narrow down the issue to styles getting messed up by the service workers and the offline plugin? The plugin is installed like:

// gatsby-config.js
// ...
module.exports = {
    // ...
    'gatsby-plugin-manifest',
    'gatsby-plugin-robots-txt',
    'gatsby-plugin-sitemap',
    'gatsby-plugin-offline',
    // ...
}

Update 2

Ok, my previous speculation about the gatsby-plugin-offline is wrong!

I'm still able to reproduce the issue and the only fix is to clear the locally stored site data through Developer Tools tab.

Another quite interesting finding is that opening links in a new tab (ctrl + click or cmd + click) actually reproduces the issue!

Still researching on a potential cause...


Update 3

I'm uploading a screenshot where the issue is clearly visible.

This is quite odd and possible the reason:

# Note jss135 and jss137
<h1 class="MuiTypography-root jss135 jss137 MuiTypography-h3 MuiTypography-gutterBottom">Yom Kippur</h1>

However, these styles are not present in the CSS inspector at all 🤔

image

@LekoArts
Copy link
Contributor

Sorry to hear that you still have problems :/ However, we can only really investigate your issue with a reproduction. If you can reproduce your issue with the starter you linked you maybe also get behind what the issue could be.

@webOS101
Copy link
Contributor

webOS101 commented Sep 18, 2019

I am having this same issue, I believe, with my site after upgrading to Gatsby 2. I since rolled back to Gatsby 1 but wanted to get back into checking this. Adding my 👍 so I can track any resolutions or contribute any help/notes. I, too, thought it might be the offline plugin, but that turned out to be a false lead.

@webOS101
Copy link
Contributor

Here's the project repository for our docs site: https://github.com/enactjs/docs/tree/feature/v2-migration

@webOS101
Copy link
Contributor

Noting that #10370 appears to be a similar issue.

@jamessimone
Copy link
Contributor

#8560 there are many related issues but this is one of the most consistently mentioned ones. You can “solve” the problem by wrapping the components whose CSS is not rendering correctly on first page load, as mentioned in the linked issue, but obviously it’s not ideal

@eyalroth
Copy link
Contributor

eyalroth commented Sep 25, 2019

Sounds very much like #14601. I'm experiencing this again, this time non-deterministically and without a clear workaround.

I believe this is currently a CRITICAL (not major) bug with Gatsby, and shouldn't be overlooked as it did before. This is likely not a bug with any particular plugin, but rather a design problem that was caused by changes to React's hydration introduced in version 16 (see #14601 for more on that).

@DSchau your thoughts?

@eyalroth
Copy link
Contributor

Actually, looks like there is a much older ticket for this issue - #8560.

@SMerdzhanov
Copy link
Author

Hey @eyalroth, thank you for sharing these threads. I re-read the comments there, but still, it seems like there's neither a clear understanding nor a solution.

We're still experiencing this issue and my thoughts about it are currently scoped to:

  • Incorrectly generated and assigned className values. For instance on gatsby build it generates jss10, but inspecting the code it should really be jss20. As simply described in this comment.

  • I think that the non-deterministic class names play some role too. So far I haven't found any easy and global solution on how to make class names deterministic. This would ensure consistent class names and the issue should be gone. However, going through dozens of components to hard-code a class name seems quite ineffective "solution". In addition to that, the non-deterministic class names, prevent us from using some other services (e.g. Google Optimize's A/B testing) because it relies on selectors which are typically a combination of HTML tags and CSS class names.

  • Ordering of the imports was my initial guess, but even with injectFirst: true in gatsby-plugin-material-ui the glitch is still there. In our project, we don't use any other styling solution like for instance styled-components so changing the order doesn't make much sense. However, I tried it and it didn't resolve anything.

  • At some point, I thought it might be something cache-related. So with or without gatsby-plugin-offline it still happens. And I tested it in any possible way I could think of.

--

There's one more thing I found out. Might be a false signal, but worth mentioning. Here's the explanation:

As per my understanding, Material UI's Core package uses the Styles package internally. So we dropped @material-ui/styles from our dependencies as needless. Then we did all of our imports from the Core package and not from Styles package. E.g.

// instead of
import ... from '@material-ui/styles';
// do
import ... from '@material-ui/core/styles/makeStyles';

However, I reviewed the example integration in this repository and noticed that it still uses Styles instead of core. So we rolled back and imported styles-related modules from the Styles package.

// rollback to Styles
// instead of
import ... from '@material-ui/core/styles/makeStyles';
// get back to
import ... from '@material-ui/styles';

Strangely it seems like the issue is happening less often now. When I get a chance this week, I'll replace all Styles-related imports like that and report back.

Again this might be non-sense, but might be helpful input.

@eyalroth
Copy link
Contributor

eyalroth commented Sep 25, 2019

@SMerdzhanov I believe this is not related to CSS per-se, but rather to any change in HTML attributes (class is just one of them). Take a look at my last comment in #8560 (posted a few minutes ago).

Do you happen do have anything in gatsby-browser.js or gatsby-ssr,js?

Edit: This could actually be due to any one of the plugins you're using. For instance, gatsby-plugin-material-ui is definitely making some work in the browser and SSR files. This might be interfering the offline plugin.

@SMerdzhanov
Copy link
Author

Hey @eyalroth, I just reviewed your comment and it makes a lot of sense!

At some point, I too thought that it's just the gatsby-plugin-offline is playing tricks. So I disabled it, followed the de-installation instructions, and verified that it's off for sure by checking the browser's DevTools and finally clearing all site data (=cache).

However, the bug still occurred. Maybe it's related, but it's a symptom rather than the cause.

I'm eager to resolve this and help in any way I can. I'm trying to fight it too! So please let me know if you want me to test, report or assist! 👍


For reference here are my gatsby-*.js files... these are basically copies of https://github.com/mui-org/material-ui/tree/master/examples/gatsby/plugins/gatsby-plugin-top-layout

// gatsby-browser.js
import React from 'react';

import 'slick-carousel/slick/slick-theme.css';
import 'slick-carousel/slick/slick.css';
import '~components/bar-bat-mitzvah/raleway-font.css';
import '~src/styles.css'; // this is 1 line of css like body { overflow-x: hidden; }

import App from './src/App'; // this is the same as https://github.com/mui-org/material-ui/blob/master/examples/gatsby/plugins/gatsby-plugin-top-layout/TopLayout.js
export const wrapRootElement = ({ element }) => <App>{element}</App>;

and

import React from 'react';
import App from './src/App';

export const wrapRootElement = ({ element }) => <App>{element}</App>;

and finally

// details and options omitted for clarity, but that's the list of all plugins
plugins: [
    {
      resolve: 'gatsby-plugin-s3',
    },
    {
      resolve: 'gatsby-source-prismic',
    },
    {
      resolve: 'gatsby-plugin-material-ui',
    },
    {
      resolve: 'gatsby-plugin-create-client-paths',
    },
    {
      resolve: 'gatsby-plugin-nprogress',
    },
    {
      resolve: 'gatsby-plugin-google-analytics',
    },
    {
      resolve: 'gatsby-plugin-facebook-pixel',
    },
    {
      resolve: 'gatsby-plugin-mailchimp',
    },
    {
      resolve: 'gatsby-plugin-manifest',
    },
    {
      resolve: 'gatsby-plugin-root-import',
    },
    'gatsby-plugin-react-helmet',
    'gatsby-plugin-robots-txt',
    'gatsby-plugin-sitemap',
    'gatsby-plugin-offline',
    'gatsby-plugin-webpack-size'
  ]

@eyalroth
Copy link
Contributor

@SMerdzhanov I really don't know why it still persists without the offline plugin. Honestly, I'm pretty new with Gatsby / React / JavsScript.

You could try to isolate the bug by removing plugins and code step by step until the bug disappears. This is what I did with my site until I found the minimum code required to reproduce the problem.

@eyalroth
Copy link
Contributor

@SMerdzhanov One more thing before you start deleting code to detect the source of the bug. Can you make sure to disable the offline plugin in the following way?

  1. Remove / comment it out from gatsby-config.js.
  2. Delete the Gatsby cache folder (.cache).
  3. Rebuild and serve the website.
  4. Try to reproduce the bug in a new incognito window.

This is what I did when I wanted to make sure that the offline plugin is the culprit. Perhaps you didn't make one of these steps. Also, I didn't use the "uninstall" plugin for the service worker.

@SMerdzhanov
Copy link
Author

@eyalroth just followed your instructions like

  1. Commented out gatsby-plugin-offline from my gatsby-config.js
  2. Deleted both .cache/ and public/ folders from the project so we start clean
  3. gatsby build and then gatsby serve
  4. Try to reproduce in incognito

Testing for like 10 min did not trigger the glitch which is promising, but I wouldn't count on it, because it's quite tricky to reproduce anyway. I found quite surprising that opening a link in a new tab through cmd/ctrl + click usually did that, but in this case, it didn't.

Let's assume that's it, meaning that gatsby-plugin-offline is playing some tricks. Do you have any thoughts on the potential reasoning behind it?

--

I can probably make an experiment and push this live with disabled offline mode. To achieve that I'll have to use the "uninstall" plugin we both mentioned. There it will be exposed to many more users and I can verify it with more certainty.

I might be able to do that tomorrow and update this thread.

@webOS101
Copy link
Contributor

As someone mentioned, it's not restricted to className. I tried at one point adding an id field to a component and the id also got duplicated to another element on the page.

@eyalroth
Copy link
Contributor

Guys, can you try applying the workaround I just posted in #8560 (replacing the hydrate method with render)?

@eyalroth
Copy link
Contributor

Also, I believe this to be exactly the same issue as #8237. There's a comment there suggesting that the "replace hydrate" workaround should solve the issue.

@SMerdzhanov
Copy link
Author

Hey @eyalroth, I see issue #17914 that you created and can't agree more. I will follow it.

I'm just pushing live the replaced hydration workaround you suggested. Note that I haven't turned off gatsby-plugin-offline, so it's still up & running.

// gatsby-browser.js
import ReactDOM from 'react-dom';
...
export function replaceHydrateFunction() {
  return (element, container, callback) => {
    ReactDOM.render(element, container, callback);
  };
}

I did gatsby build && gatsby serve and then tested it for a while. No glitches so far, but I don't trust that since the issue is quite hard to catch.

I still can't find a good way to reproduce it every time so we can debug it properly.

Anyway, I'll try to get more people testing it and will report when there's an update.

@webOS101
Copy link
Contributor

webOS101 commented Sep 27, 2019

The replacement of the hydrate function worked for me. Fortunately, that uncovered a bug that I had in my code that was causing the deployed and re-rendered version of the site to actually be different from what the server side rendered code was. So, I think if I can address that bug I might can fix the rehydrate issue I was seeing.

@SMerdzhanov
Copy link
Author

Hey @webOS101, how did you replicate and verify the fix so I can try it out too?

Do you think that this uncovered bug might be affecting someone else too? If so, can you please share it so we all look into this possibility?

@webOS101
Copy link
Contributor

webOS101 commented Sep 27, 2019

I think the bug is pretty specific to some shenanigans I'm pulling to make Gatsby run in directories other than the one the deploy command specifies with pathPrefix. In Gatsby 1, there was a global variable __PREFIX_PATHS__ that was apparently removed in Gatsby 2. We wrote some helper functions to normalize location.pathname and that code failed in Gatsby 2 because it thought there was no path prefix so it was failing to use the right page template for some files, causing the output to be not what was expected. I never discovered it because the path prefix isn't needed when using develop or even build.

@LekoArts
Copy link
Contributor

Let's keep discussing in the "Meta" issue as writing across multiple different issues is just really cumbersome. #17914

@eyalroth
Copy link
Contributor

@SMerdzhanov I linked a repository to reproduce the problem in both #8560 and #17914.

My process for reproducing the problem was, as I mentioned earlier, cutting off parts of my site (perhaps the dev branch is more appropriate) until I saw the problem gets solved, in order to understand which part is causing the problem.

I did that in conjunction with another repository cloned from the default gatsby starter, which I modified to eventually contain all (and only) the parts that caused the problem in my site.

@IsaiahByDayah
Copy link

Hey hey, just wanted to post for clarity/shared knowledge?

I'm currently building a Gatsby + MUI site with dynamic client-side routes and am experiencing some issues when my page gets rehydrated. Initial load to /something/:dynamic is fine (SSR looks as expected) but seemingly as soon as it's rehydrated and my MUI components are mounted, custom styles get overwritten/disappear causing the page to look messed up ¯_(ツ)_/¯

I tried the solution mentioned above by @eyalroth and replaced my hydrate function with a rerender and that seems to have fixed my problems but I agree that that might be more of a workaround than a solution. I just wanted to post here since I found this thread in my search for an answer.

Best of luck!

@blainekasten
Copy link
Contributor

#25729

@monsieurBoutte
Copy link

monsieurBoutte commented Nov 23, 2020

not sure why this is closed. I had to implement the same workaround

// gatsby-browser.js
import ReactDOM from 'react-dom'

// this is a hack to fix missing styles on refresh in production
// reference: https://github.com/gatsbyjs/gatsby/issues/17676#issuecomment-535796737
export function replaceHydrateFunction() {
  return (element, container, callback) => {
    ReactDOM.render(element, container, callback)
  }
}

@anthonytison
Copy link

@SMerdzhanov Thx!! I banged my head for hours on this.

@eyalroth
Copy link
Contributor

@monsieurBoutte @anthonytison This issue is tracked in #17914.

@visualjeff
Copy link

Installing this Gatsby plugin resolved the issue for me: https://www.gatsbyjs.com/plugins/gatsby-plugin-material-ui/

@erroldtumaque
Copy link

This was hurting my head for hours. I can't believe it, it was because I used class={} instead of className={} for one of my components.

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: bug An issue or pull request relating to a bug in Gatsby
Projects
None yet
Development

No branches or pull requests