segmentio / evergreen

🌲 Evergreen React UI Framework by Segment
https://evergreen.segment.com
MIT License
12.38k stars 830 forks source link

Next.js + Evergreen FOUC on Hard Refresh #1538

Closed ZaneH closed 1 year ago

ZaneH commented 1 year ago

I'm working on a project and I notice on the first load it flashes unstyled content. It's rather jarring on a large scale.

I've created some GIFs and provided a repo that shows this issue pretty well.

Here is Next.js + styled-components hard refreshing (looks good):

https://user-images.githubusercontent.com/8400251/197290993-63aacec6-47dd-4c4b-b389-b01a26d90ef2.mov

And this is Next.js + Evergreen + styled-components:

https://user-images.githubusercontent.com/8400251/197291042-892fe2e6-0075-4378-9b3c-38aa0bf887ac.mov


I'm triggering a hard refresh on both to emulate a first load. Here is the repo containing the code for these Minimum Reproducibles: https://github.com/ZaneH/mre-fouc Here's the link to my _document.js that injects the evergreen styles: https://github.com/ZaneH/mre-fouc/blob/master/mre-fluc-2/pages/_document.js both are using SWR.

brandongregoryscott commented 1 year ago

Here's the link to my _document.js that injects the evergreen styles: ZaneH/mre-fouc@master/mre-fluc-2/pages/_document.js

I'm not seeing any reference to extractStyles from evergreen-ui in there! I'm only seeing references to the styled-components stylesheet. I can't promise they [styled-components + evergreen-ui] will play well together, but I think you'll need to render the <style> tag with the css returned from extractStyles, and the hydrationScript, as demonstrated in our SSR example:

https://github.com/segmentio/evergreen/blob/e838425a67fd8e211dbba898cbd4fa7f2ff1e11b/examples/ssr-next/pages/_document.js#L9-L42

ZaneH commented 1 year ago

That was a very helpful reminder! I've had to make some minor changes for it to fit with styled-components but it appears to be completely fixed with the following:

import { extractStyles } from 'evergreen-ui'
import Document, { Head, Html, Main, NextScript } from 'next/document'
import { ServerStyleSheet } from 'styled-components'

export default class MyDocument extends Document {
  static async getInitialProps(ctx) {
    const sheet = new ServerStyleSheet()
    const originalRenderPage = ctx.renderPage

    try {
      ctx.renderPage = () =>
        originalRenderPage({
          enhanceApp: (App) => (props) =>
            sheet.collectStyles(<App {...props} />),
        })

      const page = await ctx.renderPage()
      const initialProps = await Document.getInitialProps(ctx)
      const { css, hydrationScript } = extractStyles()
      return {
        ...initialProps,
        ...page,
        css,
        hydrationScript,
        styles: [initialProps.styles, sheet.getStyleElement()],
      }
    } finally {
      sheet.seal()
    }
  }

  render() {
    const { css, hydrationScript } = this.props

    return (
      <Html>
        <Head>
          {/** ...snip... **/}
          <style dangerouslySetInnerHTML={{ __html: css }} />
        </Head>
        <body>
          <Main />
          {hydrationScript}
          <NextScript />
        </body>
      </Html>
    )
  }
}
ZaneH commented 1 year ago

I've noticed that this results in glitchy Tooltips (from Evergreen), I'll open a new issue if I can't find a fix