Как выполнить предварительную визуализацию материала-UI v5 с Next.js ?

#reactjs #material-ui #next.js #emotion

#reactjs #материал-пользовательский интерфейс #next.js #эмоции

Вопрос:

Я пытаюсь создать следующее приложение, которое использует многомерные выражения для создания страниц и материалов -UI v5 Emotion, и я хочу, чтобы оно работало даже с отключенным JavaScript через статическую генерацию сайта. Я последовал этому примеру из репозитория Material UI, чтобы продолжить, но я застрял. Стили не применяются одинаково хорошо, когда JS отключен.

Вот как это выглядит с включенным JS: JS: Включен

И вот как это выглядит с отключенным JS: JS: отключен

Соответствующие файлы:

_document.tsx

 import React from "react";
import Document, {
  Html,
  Head,
  Main,
  NextScript,
  DocumentContext,
} from "next/document";
import { ServerStyleSheets } from "@material-ui/core/styles";
import createEmotionServer from "@emotion/server/create-instance";
import theme from "../styles/theme";
import { cache } from "./_app";

const { extractCritical } = createEmotionServer(cache);

class MyDocument extends Document {
  static async getInitialProps(ctx: DocumentContext) {
    // 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);
    const styles = extractCritical(initialProps.html);

    return {
      ...initialProps,
      // Styles fragment is rendered after the app and page rendering finish.
      styles: [
        ...React.Children.toArray(initialProps.styles),
        sheets.getStyleElement(),
        <style
          key="emotion-style-tag"
          data-emotion={`css ${styles.ids.join(" ")}`}
          // eslint-disable-next-line react/no-danger
          dangerouslySetInnerHTML={{ __html: styles.css }}
        />,
      ],
    };
  }

  render() {
    return (
      <Html lang="en">
        <Head>
          <meta
            name="description"
            content="A template for creating amazing docs for your projects"
          />
          <meta name="theme-color" content={theme.palette.primary.main} />
          <link
            rel="stylesheet"
            href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700amp;display=swap"
          />
        </Head>
        <body>
          <Main />
          <NextScript />
        </body>
      </Html>
    );
  }
}

export default MyDocument;
 

_app.tsx:

 import React from "react";
import { ThemeProvider } from "@material-ui/core/styles";
import CssBaseline from "@material-ui/core/CssBaseline";
import { Container } from "@material-ui/core";
import type { AppProps } from "next/app";
import { MDXProvider } from "@mdx-js/react";
import CodeBlock from "../components/CodeBlock";
import AppBar from "../components/AppBar";
import theme from "../styles/theme";
import Head from "next/head";
import { CacheProvider } from "@emotion/react";
import createCache from "@emotion/cache";

export const cache = createCache({ key: "css", prepend: true });

export default function App(props: AppProps) {
  const { Component, pageProps } = props;

  React.useEffect(() => {
    // Remove the server-side injected CSS.
    const jssStyles = document.querySelector("#jss-server-side");
    if (jssStyles) {
      jssStyles.parentElement!.removeChild(jssStyles);
    }
  }, []);

  return (
    <CacheProvider value={cache}>
      <Head>
        <title>Next.js Doc creator</title>
        <meta name="viewport" content="initial-scale=1, width=device-width" />
      </Head>
      <ThemeProvider theme={theme}>
        <CssBaseline />
        <MDXProvider
          components={{
            code: CodeBlock,
          }}
        >
          <AppBar />
          <Container>
            <Component {...pageProps} />
          </Container>
        </MDXProvider>
      </ThemeProvider>
    </CacheProvider>
  );
}
 

компоненты/AppBar.tsx:

 import { createStyles, makeStyles, Theme } from '@material-ui/core/styles';
import { AppBar, Button, IconButton, Toolbar, Typography } from "@material-ui/core";
import MenuIcon from "@material-ui/icons/Menu";

const useStyles = makeStyles((theme: Theme) => createStyles({
    root: {
      flexGrow: 1,
    },
    menuButton: {
      marginRight: theme.spacing(2),
    },
    title: {
      flexGrow: 1,
    },
  }));

function MainAppBar() {
    const classes = useStyles()
  return (
    <AppBar position="static">
      <Toolbar>
        <IconButton
          edge="start"
          className={classes.menuButton}
          color="inherit"
          aria-label="menu"
        >
          <MenuIcon />
        </IconButton>
        <Typography variant="h6" className={classes.title} component="div">
          Your Awesome App
        </Typography>
      </Toolbar>
    </AppBar>
  );
}

export default MainAppBar;
 

PS: Я использую next build amp;amp; next export в своем package.json для SSG.

Комментарии:

1. Может ли это быть связано App с useEffect тем, что хук не запускается, когда JS отключен?

2. Можете ли вы попробовать стилизовать свой компонент без использования makeStyles?