升级到Material UI 5(使用Next.js)后服务器端渲染中断

xiozqbni  于 2023-05-22  发布在  其他
关注(0)|答案(4)|浏览(116)

我将我的服务器端渲染(SSR)工作应用程序迁移到MUI版本5。我跟踪了official procedure,但是当我禁用JavaScript时,我收到了一个原始的HTML页面(没有CSS)。你可以看到它here(对不起,如果它的下降;我经常重新部署以进行测试)。
1.运行codemod(v5.0.0/preset-safe和link-underline-hover)
1.将makeStyles调用更改为使用tss-react
1.根据MUI example with Next.js修改了我的 _app_document 文件
我推出了官方的SSR Next.js implementation。它表明它也不起作用。

有关详细信息,以下是我的项目中的关键文件:

_app.js

import * as React from 'react';
import Head from 'next/head';
import {ThemeProvider} from '@mui/material/styles';
import CssBaseline from '@mui/material/CssBaseline';
import {CacheProvider} from '@emotion/react';
import theme from '../components/theme';
import createEmotionCache from "../lib/createEmotionCache";
import {StyledEngineProvider} from '@mui/material/styles';
import {ApolloProvider} from "@apollo/client";
import {SessionProvider} from "next-auth/react"
import {appWithTranslation} from "next-i18next";
import {useApollo} from "../apollo/client";
// Client-side cache, shared for the whole session of the user in the browser.
const clientSideEmotionCache = createEmotionCache();

//followed example: https://github.com/mui/material-ui/tree/master/examples/nextjs
function App(props) {
    const {Component, emotionCache = clientSideEmotionCache, pageProps} = props;
    const apolloClient = useApollo(pageProps)

    return (
        <CacheProvider value={emotionCache}>
            <StyledEngineProvider injectFirst>
                <ApolloProvider client={apolloClient}>
                    <SessionProvider session={pageProps.session}>
                        <Head>
                            <meta name="viewport" content="initial-scale=1, width=device-width"/>

                            <title>WeAlly</title>
                            <meta name="viewport" content="minimum-scale=1, initial-scale=1, width=device-width"/>
                            <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon.png"/>
                            <link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32.png"/>
                            <link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16.png"/>
                            <link rel="manifest" href="/images/site.webmanifest"/>
                        </Head>

                        <ThemeProvider theme={theme}>
                            {/* CssBaseline kickstart an elegant, consistent, and simple baseline to build upon. */}
                            <CssBaseline/>
                            <Component {...pageProps} />
                        </ThemeProvider>
                    </SessionProvider>
                </ApolloProvider>
            </StyledEngineProvider>
        </CacheProvider>
    );
}

export default appWithTranslation(App);

_document.js

import * as React from 'react';
import Document, { Html, Head, Main, NextScript } from 'next/document';
import createEmotionServer from '@emotion/server/create-instance';
import theme from '../components/theme';
import createEmotionCache from "../lib/createEmotionCache";

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="shortcut icon" href="/static/favicon.ico" />
                    <link
                        rel="stylesheet"
                        href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap"
                    />
                    <link rel="preconnect" href="https://fonts.googleapis.com"/>
                    <link rel="preconnect" href="https://fonts.gstatic.com"/>
                    <link href="https://fonts.googleapis.com/css2?family=Ubuntu:wght@300;400;700&display=swap"
                          rel="stylesheet"/>

                    <link
                        href="https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,300;0,400;0,600;1,400&display=swap"
                        rel="stylesheet"/>

                    <link rel="stylesheet"
                          href="https://fonts.googleapis.com/icon?family=Material+Icons&display=swap"
                          media="screen"/>
                    {/* Inject MUI styles first to match with the prepend: true configuration. */}
                    {this.props.emotionStyleTags}
                </Head>
                <body>
                <Main />
                <NextScript />
                </body>
            </Html>
        );
    }
}

// `getInitialProps` belongs to `_document` (instead of `_app`),
// it's compatible with static-site generation (SSG).
MyDocument.getInitialProps = async (ctx) => {
    const originalRenderPage = ctx.renderPage;

    // You can consider sharing the same emotion cache between all the SSR requests to speed up performance.
    // However, be aware that it can have global side effects.
    const cache = createEmotionCache();
    const { extractCriticalToChunks } = createEmotionServer(cache);

    ctx.renderPage = () =>
        originalRenderPage({
            enhanceApp: (App) =>
                (function EnhanceApp(props) {
                    // console.log( 'enhancing app with cache: ', cache )
                    return <App emotionCache={cache} {...props} />;
                }),
        });

    const initialProps = await Document.getInitialProps(ctx);
    // This is important. It prevents emotion from rendering invalid HTML.
    // See https://github.com/mui/material-ui/issues/26561#issuecomment-855286153
    const emotionStyles = extractCriticalToChunks(initialProps.html);
    // console.log('emotion style count: ', emotionStyles.styles.length)
    const emotionStyleTags = emotionStyles.styles.map((style) => (
        <style
            data-emotion={`${style.key} ${style.ids.join(' ')}`}
            key={style.key}
            // eslint-disable-next-line react/no-danger
            dangerouslySetInnerHTML={{ __html: style.css }}
        />
    ));

    return {
        ...initialProps,
        emotionStyleTags,
    };
};

**package.json**

{
  "name": "we-ally-org",
  "version": "1.0.0",
  "scripts": {
    "dev": "next",
    "back": "node ./server/starter.js",
    "build": "next build",
    "start": "next start"
  },
  "dependencies": {
    "@apollo/client": "^3.4.17",
    "@emotion/react": "^11.8.2",
    "@emotion/styled": "^11.8.1",
    "@google/maps": "^1.1.3",
    "@hapi/iron": "6.0.0",
    "@mui/icons-material": "^5.5.1",
    "@mui/material": "^5.5.2",
    "@mui/styles": "^5.5.1",
    "@next-auth/mongodb-adapter": "^1.0.3",
    "@next/bundle-analyzer": "^11.1.0",
    "@prisma/client": "2.16.1",
    "apollo-server-micro": "^3.5.0",
    "axios": "^0.21.1",
    "body-parser": "^1.19.0",
    "classnames": "^2.3.1",
    "cookie": "^0.4.1",
    "cors": "^2.8.5",
    "deepmerge": "4.2.2",
    "ejs": "^3.1.6",
    "express-graphql": "^0.12.0",
    "express-jwt": "^6.0.0",
    "express-session": "^1.17.2",
    "google-map-react": "^2.1.9",
    "graphql": "^15.5.1",
    "graphql-tools": "^8.1.0",
    "graphql-ws": "^5.4.0",
    "http-proxy": "^1.18.1",
    "image-type": "^4.1.0",
    "jodit-react": "^1.1.1",
    "jsonwebtoken": "^8.5.1",
    "linkify-react": "^3.0.4",
    "linkifyjs": "^3.0.5",
    "lodash": "^4.17.21",
    "micro": "^9.3.4",
    "moment": "^2.29.1",
    "mongodb": "^4.4.1",
    "next": "12",
    "next-auth": "^4.3.1",
    "next-compose-plugins": "^2.2.1",
    "next-i18next": "^8.5.1",
    "node-fetch": "^3.0.0",
    "passport": "^0.4.1",
    "passport-facebook": "^3.0.0",
    "pino": "^6.11.3",
    "prop-types": "^15.6.2",
    "react": "^17.0.2",
    "react-dom": "^17.0.2",
    "react-ga": "^3.3.0",
    "react-image-gallery": "^1.2.7",
    "react-moment": "^1.1.1",
    "react-player": "^2.9.0",
    "react-share": "^4.4.0",
    "react-use": "^17.2.4",
    "sanitize-html": "^2.4.0",
    "subscriptions-transport-ws": "^0.9.19",
    "tss-react": "^3.6.0"
  },
  "license": "MIT",
  "devDependencies": {
    "@babel/core": "^7.15.5",
    "@emotion/server": "^11.4.0",
    "babel-plugin-styled-components": "^2.0.6",
    "eslint": "8.11.0",
    "eslint-config-next": "12.1.0"
  }
}

另外,一个依赖库被破坏:react-image-gallerydisplays incorrectly自从升级以来,但我仍然没有深入研究。

t0ybt7op

t0ybt7op1#

我的问题是React 18。在package.json中恢复到React 17\

"dependencies": {
        "react": "17.0.2",
        "react-dom": "17.0.2"
dgtucam1

dgtucam12#

这是一个Next.js问题,自12.1.7-canary.4及更高版本以来已经解决。

cxfofazt

cxfofazt3#

我解决了这个问题与加载启动画面时,启动画面被摧毁一切正常,样式完全加载an article about splash screen in nextjs

ibps3vxo

ibps3vxo4#

今天,我一直在努力解决我这边的这个问题,我找到了解决方案。你应该从应用中删除你的StyledEngineProvider,并修改你的情绪缓存为:

import createCache from '@emotion/cache';

// prepend: true moves MUI styles to the top of the <head> so they're loaded first.
// It allows developers to easily override MUI styles with other styling solutions, like CSS modules.
export const createEmotionCache = () =>
  createCache({ key: 'css', prepend: true });

我以前不明白StyledEngineProvider在做什么,但它改变了CSS顺序,并将MUI样式添加到头部的顶部,但如果你在缓存解决方案中添加prepend=true,你就不再需要它了。看这个链接。

相关问题