Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Preloading a .css file with NextJS

We are using NextJS and Material-UI for our site, and upon loading the pages, it gives a FOUC. I've narrowed the problem down to the fact that the JS loads faster than the .css file, so I was wondering if there was a way to preload the .css file? All of our pages use the same .css file which is located under /pages/styles.css

Here is /pages/_app.js if that's any help:

// pages/_app.js
import { Provider } from 'next-auth/client'
import { createMuiTheme } from '@material-ui/core/styles';
import { ThemeProvider } from '@material-ui/styles';
import styles from './styles.css'

import Layout from '../components/layout'
import Head from 'next/head'

const theme = createMuiTheme({
  palette: {
    primary: {
      main: "#2196f3", // blue
    },
    secondary: {
      main: "#d3d3d3", // gray
    },
  },
});

export default function _App ({ Component, pageProps }) {
  return (
    <ThemeProvider theme={theme}>
      <Provider options={{ clientMaxAge: 0, keepAlive: 0 }} session={pageProps.session}>
        <Layout>  
          {/* Head */}
          <Head>
            <title>Kevin Support</title>
            <link rel="icon" href="/static/favicon.png"/>
          </Head>

          {/* Page */}
          <Component {...pageProps} />
        </Layout>
      </Provider>
    </ThemeProvider>
  )
}
like image 437
alexover1 Avatar asked Jul 09 '26 11:07

alexover1


1 Answers

Perhaps styles weren't applied on the server-side. Try to add _document.js from Material-UI's Next.js example. Adjust it to your needs.

// pages/_document.js
import React from 'react';
import Document, { Html, Head, Main, NextScript } from 'next/document';
import { ServerStyleSheets } from '@material-ui/core/styles';
import theme from '../src/theme';

export default class MyDocument extends Document {
  render() {
    return (
      <Html lang="en">
        <Head>
          {/* PWA primary color */}
          <meta name="theme-color" content={theme.palette.primary.main} />
          <link
            rel="stylesheet"
            href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap"
          />
        </Head>
        <body>
          <Main />
          <NextScript />
        </body>
      </Html>
    );
  }
}

// `getInitialProps` belongs to `_document` (instead of `_app`),
// it's compatible with server-side generation (SSG).
MyDocument.getInitialProps = async (ctx) => {
  // Resolution order
  //
  // On the server:
  // 1. app.getInitialProps
  // 2. page.getInitialProps
  // 3. document.getInitialProps
  // 4. app.render
  // 5. page.render
  // 6. document.render
  //
  // On the server with error:
  // 1. document.getInitialProps
  // 2. app.render
  // 3. page.render
  // 4. document.render
  //
  // On the client
  // 1. app.getInitialProps
  // 2. page.getInitialProps
  // 3. app.render
  // 4. page.render

  // Render app and page and get the context of the page with collected side effects.
  const sheets = new ServerStyleSheets();
  const originalRenderPage = ctx.renderPage;

  ctx.renderPage = () =>
    originalRenderPage({
      enhanceApp: (App) => (props) => sheets.collect(<App {...props} />),
    });

  const initialProps = await Document.getInitialProps(ctx);

  return {
    ...initialProps,
    // Styles fragment is rendered after the app and page rendering finish.
    styles: [...React.Children.toArray(initialProps.styles), sheets.getStyleElement()],
  };
};

Also, you can try to remove server-side injected CSS in the _app.js like so (see example):

React.useEffect(() => {
    // Remove the server-side injected CSS.
    const jssStyles = document.querySelector('#jss-server-side');
    if (jssStyles) {
      jssStyles.parentElement.removeChild(jssStyles);
    }
  }, []);
like image 103
Nikolai Kiselev Avatar answered Jul 11 '26 02:07

Nikolai Kiselev



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!