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

Flash of unstyled Content when running via build and serve #215

Open
bmaycc opened this issue Jun 23, 2022 · 20 comments · May be fixed by #223
Open

Flash of unstyled Content when running via build and serve #215

bmaycc opened this issue Jun 23, 2022 · 20 comments · May be fixed by #223
Assignees
Labels
bug Something isn't working builds

Comments

@bmaycc
Copy link

bmaycc commented Jun 23, 2022

Hi,

First, thanks very mich @rohit-gohri for the excellent tool! Really helpful!!

Got a weird FOUC (flash of unstyled content) issue - we're using redocusaurus in a locally built instance.

I noticed that on the deployed site (https://redocusaurus.vercel.app/examples/) there's no problem, BUT if if I download the code and run the example locally:

yarn build && yarn serve

Then go to an API page, and refresh the page, it does something like this for a second, then the site resolves itself (I'm guessing due to late loading of css?). This is identical to what I'm seeing in my instance.
image

Another note here is if I run the app in 'dev mode' via yarn start there's no issue.

(btw, if there's ideas on where to look but it's a bit complicated, I'm happy to help with a PR)

Any ideas?

@bmaycc
Copy link
Author

bmaycc commented Jul 4, 2022

Update: I noticed this only occurs in dark mode, and it does happen on the vercel site https://redocusaurus.vercel.app/examples/ when you switch, so it must be related to the theme. I'll check this out further

@rohit-gohri rohit-gohri added bug Something isn't working builds labels Jul 10, 2022
@mfaux
Copy link

mfaux commented Jul 14, 2022

Possibly related. After building my site (npm run build) and then serving the content (npx serve), the search icon fills the page until the page has loaded:

large

I've tested this with:

Note that you won't experience the bug when running npm start; only when serving the built content.

p.s. Thank you for your work @rohit-gohri 🙇‍♂️

@bmaycc
Copy link
Author

bmaycc commented Jul 15, 2022

Yes @mfaux this is exactly what I saw as well. Interestingly for me, light mode was not as problematic on this as dark mode. For the time being, I'm deployed using npm start and while it's not ideal, it works ok.

Also in his vercel deployment, the problem only appears clearly in the dark mode setting, not light mode. Sorry been a bit busy on other things to get time to get back to this, but I'd welcome any ideas.

@rohit-gohri
Copy link
Owner

The problem is definitely with the ServerStyles and hydration. I suspect when react hydrates it removes the server style and then computes fresh styles in js. If we can somehow persist the server styles (maybe remove them after react has hydrated?) then I think it would solve this issue

@bmaycc
Copy link
Author

bmaycc commented Jul 15, 2022

@rohit-gohri thanks for the insight - does it use a completely separate model than the base docusaurus docs build, which doesn't have this issue?

@rohit-gohri
Copy link
Owner

We render the styles component only on server - https://github.com/rohit-gohri/redocusaurus/blob/main/packages/docusaurus-theme-redoc/src/theme/Redoc/ServerStyles.tsx by modifying the webpack config only if it's a server build here -

...(isServer
? [
new webpack.NormalModuleReplacementPlugin(
/theme\/Redoc\/Styles/,
path.join(__dirname, 'theme', 'Redoc', 'ServerStyles.js'),
),
]
: []),

On client it renders an empty div - https://github.com/rohit-gohri/redocusaurus/blob/main/packages/docusaurus-theme-redoc/src/theme/Redoc/Styles.tsx

What I was trying to use do was use this approach - facebook/react#10923 (comment) and skip hydration for the styles component altogether but couldn't get it to work

@bmaycc
Copy link
Author

bmaycc commented Jul 15, 2022

Got it - thanks a lot for the insight. Will definitely be interested to investigate further when I have a free moment.

@rohit-gohri rohit-gohri linked a pull request Jul 15, 2022 that will close this issue
@rohit-gohri
Copy link
Owner

Turns out that is not the problem. Fixed the hyrdation issue in #223 but this issue is still there because all the class names change when client code loads

@rohit-gohri
Copy link
Owner

That can be fixed by adding babel-plugin-styled-components to the user's babel.config.js file.

Can you try the release at https://redocusaurus-dcul1rve3-rohit-gohri.vercel.app/ to see if you can reproduce the issue?

And if not then you can try this test release in your project to see if it fixes the issue

yarn add [email protected] babel-plugin-styled-components@^2

And then adding babel-plugin-styled-components to babel.config

module.exports = {
  presets: [require.resolve('@docusaurus/core/lib/babel/preset')],
  plugins: ['babel-plugin-styled-components']
};

@rohit-gohri rohit-gohri self-assigned this Jul 15, 2022
@bmaycc
Copy link
Author

bmaycc commented Jul 15, 2022

HI @rohit-gohri problem still exists - I'm happy to do a screen share if you'd like to discuss further. The problem on that link still does not happen in light mode, only in dark mode.

I assume you're not able to reproduce this?

@rohit-gohri
Copy link
Owner

I was using Firefox, there I could not reproduce. Checked in Chrome now, reproducible very easily.
But I think the changes are in the right direction. Will work on it later now.

@bmaycc
Copy link
Author

bmaycc commented Jul 15, 2022

Awesome, thanks again for digging in! Strangely, I just tried on Firefox (on latest MacOS, v102.0.1), and I see the problem there as well (on your Vercel link)

@srweeks
Copy link

srweeks commented Oct 7, 2022

hey @rohit-gohri, any progress on this issue?

@Snivio
Copy link
Contributor

Snivio commented Oct 10, 2022

Work around
create a plugin and add a custom loader



module.exports = function (context, options) {
    return {
        name: 'redocusaurus-preload',
        injectHtmlTags() {
            return {
                preBodyTags: [
                    `
                    <script>
                    let isPath = [the redocusorus paths].includes(location.pathname)
                  

                    if ((window.performance && performance.navigation.type == performance.navigation.TYPE_RELOAD || window.performance && performance.navigation.type == performance.navigation.TYPE_NAVIGATE) && isPath) {
                        showRedocFrag(false);
                    } 
                    function showRedocFrag(toggle){
                        const range = document.createRange()
                        const displayContent = toggle?'block':'none';
                        const displayLoader = !toggle?'block':'none';
                        const frag = range.createContextualFragment(\`
                            <style>
                                .redocusaurus{
                                display: \${displayContent};
                                }
                                .redocusaurus-styles,
                                .redocusaurus-styles:after {
                                      border-radius: 50%;
                                      margin-top: 30vh !important;
                                      margin-bottom: 50vh !important;
                                      width: 10em;
                                      height: 10em;
                                    }
                                    .redocusaurus-styles {
                                      display: \${displayLoader};
                                      margin: 60px auto;
                                      font-size: 10px;
                                      position: relative;
                                      text-indent: -9999em;
                                      border-top: 1.1em solid rgba(255, 255, 255, 0.2);
                                      border-right: 1.1em solid rgba(255, 255, 255, 0.2);
                                      border-bottom: 1.1em solid rgba(255, 255, 255, 0.2);
                                      border-left: 1.1em solid #ffffff;
                                      -webkit-transform: translateZ(0);
                                      -ms-transform: translateZ(0);
                                      transform: translateZ(0);
                                      -webkit-animation: load8 1.1s infinite linear;
                                      animation: load8 1.1s infinite linear;
                                    }
                                    @-webkit-keyframes load8 {
                                      0% {
                                        -webkit-transform: rotate(0deg);
                                        transform: rotate(0deg);
                                      }
                                      100% {
                                        -webkit-transform: rotate(360deg);
                                        transform: rotate(360deg);
                                      }
                                    }
                                    @keyframes load8 {
                                      0% {
                                        -webkit-transform: rotate(0deg);
                                        transform: rotate(0deg);
                                      }
                                      100% {
                                        -webkit-transform: rotate(360deg);
                                        transform: rotate(360deg);
                                      }
                                    }
                            </style>
                            \`
                            )
                            document.querySelector("head").append(frag)
                    }
                    </script>
                `
                ],
                postBodyTags: [
                    `
                    <script>
                    let hasPath = [the redocusorus paths].includes(location.pathname)

                    if ((window.performance && performance.navigation.type == performance.navigation.TYPE_RELOAD || window.performance && performance.navigation.type == performance.navigation.TYPE_NAVIGATE) && hasPath) {
                        let redocusaurusDoc = document.querySelector('.redocusaurus')
                        document.onreadystatechange = function() {
                            if (document.readyState === "complete") {
                                showRedocFrag(true);
                            }
                        }
                    } 
                    </script>
                `
                ],
            };
        },
    };
};

@bmaycc
Copy link
Author

bmaycc commented Oct 10, 2022

@Snivio Thank you that's a great workaround! (tip for implementers, if your whole site is docusaurus you can get rid of those hasPath/isPath variables)

For me just added plugins: ["./redocusaurusFlashWorkaroundPlugin.js"] and voila!

@rohit-gohri
Copy link
Owner

@Snivio It'll be great if you can open a PR adding that plugin to redocusaurus. I think it can go directly to the theme - https://github.com/rohit-gohri/redocusaurus/blob/main/packages/docusaurus-theme-redoc/src/index.ts

We can put it behind an option, it's a great workaround until this gets fixed

@mfaux
Copy link

mfaux commented Nov 8, 2022

A colleague came up with the following work around.

If you're using @docusaurus/preset-classic , add this to /src/css/custom.css:

/**
* Prevent redocusaurus from displaying html before its styles are fully
* loaded. This prevents large icons from being displayed before they 
* properly styled. 
*/
.redocusaurus {
  display: none;
}

body[data-rh] .redocusaurus {
  display: block;
}

@JPeer264
Copy link
Contributor

JPeer264 commented Mar 3, 2023

I got into this topic a little as we also stumbled across this. So what I could see is that this is a quite complex problem and there are two different problems:

  1. Removing of all styles: in Styles.tsx the dangerouslySetInnerHTML={{ __html: '' }} is missing which causes the styles will be removed after the client rehydrated the code (this is easy to fix). At least that was an issue we encountered (I will create a PR for that)
  2. Flicker: There is the use of ThemeProvider where the theme got hooked in (this is the main problem of this issue and actually not quite easy to fix with a static site.

I will elaborate more on issue 2. (Flicker):

When styled-components changes the themes between light and dark it certainly also changes every class where the theme is attached such as here (redocusaurus changes theme.schema.arrow.color in the theme config, ergo the entire classname is totally different, I will come later to the problem of this).

So now there is the rendering of docusaurus website which is only once per buildtime and usually it is only for the light theme (since there is usually only one build). There is a smart logic of redocusaurus to provide the CSS for light AND dark theme into the HTML and the CSS classes are also prefixed with either html:not([data-theme='dark']) or html([data-theme='dark']) which would only work if the class names are the same in light AND dark theme (well I guess you see the problem now). But this is not the main reason for the flicker. The main reason for the flicker is the tiny JavaScript added by docusaurus to add data-theme="dark" as soon as possible, even before the main JavaScript is parsed and executed (you can see the script right after the <body> tag ). With that script, the dark theme styles will take action, but it does not quite match with the classnames of the document itself -> hence flicker.

Well, how can this be solved?

  1. Best would be to add css-variables and let only change the css-cariables, unfortunately this does not work as redoc does use polished and it will go 💥 on places like this.
    1. To make it work: Try to remove polished as much as possible in redoc and use things like rgba(var(--some-color), 0.8) instead of transparentize and then update everything to css-variables. This would allow to remove the theme switching in redocusaurus and just change the css variables (with this there is also less HTML for free as only one stylesheet needs to be shipped 🥳)
  2. Easiest, but well, not the prettiest: the solution from @mfaux to just don't display it until it is fully rehydrated.

FWIW. I don't think there are any other options left, as styled components would work best with SSR but docusaurus is relying on SSG.

@rohit-gohri
Copy link
Owner

@JPeer264 Thanks for the detailed deep dive on this! I have merged your PR. And it's out in v1.6.1.

For the second part I don't think redoc would implement a solution for a downstream package, so I'll keep this issue still open.

@NoahMaizels
Copy link

Another thing I think which is caused by this issue is that it makes it so the scrollYOffset redoc option isn't applied properly on a page reload. On the first page load it applies the offset correctly, but when I reload the page the offset disappears, so when I scroll down the page the search bar becomes hidden by the navbar.

Adding @mfaux's CSS fix somehow fixed this problem for me.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working builds
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants