NextJs13+MUI5+React18页面加载时MUI CSS闪烁问题求助
解决Next.js 13 + MUI 5静态导出时的CSS闪烁问题
问题核心
升级到Next.js 13和MUI 5后,静态导出(npm run build && npm run export)的页面首次加载出现CSS闪烁,且页面head中的<style data-emotion="css ">标签为空,说明服务端渲染时未正确提取并注入Critical CSS。
修复方案
1. 修正_document.js的getInitialProps逻辑
原代码中调用originalRenderPage后未接收返回值,导致后续CSS提取基于错误的渲染结果,修改后代码如下:
import Document, { Html, Head, Main, NextScript } from 'next/document' import createEmotionServer from '@emotion/server/create-instance' import createEmotionCache from '../lib/mui/createEmotionCache' class AppDocument extends Document { render() { return ( <Html lang={ this?.props?.__NEXT_DATA__?.props?.pageProps?.locale || 'en' }> <Head> <meta name="emotion-insertion-point" content="" /> {this.props.emotionStyleTags} </Head> <body style={{ margin: 0 }}> <Main /> <NextScript /> <script src='/analytics.js' /> </body> </Html> ) } } AppDocument.getInitialProps = async (ctx) => { const originalRenderPage = ctx.renderPage const cache = createEmotionCache() const { extractCriticalToChunks } = createEmotionServer(cache) // 关键:覆盖ctx.renderPage,确保使用带emotion缓存的渲染逻辑 ctx.renderPage = () => originalRenderPage({ enhanceApp: (App) => (props) => <App emotionCache={cache} {...props} />, }) const initialProps = await Document.getInitialProps(ctx) const emotionStyles = extractCriticalToChunks(initialProps.html) const emotionStyleTags = emotionStyles.styles.map((style) => ( <style data-emotion={`${style.key} ${style.ids.join(" ")}`} key={style.key} dangerouslySetInnerHTML={{ __html: style.css }} /> )) return { ...initialProps, emotionStyleTags, locale: ctx.query.locale } } export default AppDocument
2. 确认createEmotionCache配置
确保../lib/mui/createEmotionCache.js中的缓存key唯一,避免与Next.js默认样式冲突:
import createCache from '@emotion/cache' export default function createEmotionCache() { return createCache({ key: 'mui-static', prepend: true }) }
prepend: true可确保MUI样式优先加载,避免被其他样式覆盖。
3. 升级Next.js静态导出配置(Next.js 13+推荐)
在next.config.js中添加output: 'export',替代原有的npm run export命令(Next.js 13.4+官方推荐方式):
/** @type {import('next').NextConfig} */ const nextConfig = { output: 'export', // 其他项目配置... } module.exports = nextConfig
之后只需运行npm run build即可生成静态文件,无需额外执行export命令。
4. 调整_app.js的参数传递
确保_app.js正确接收服务端传递的emotion缓存:
import { ThemeProvider } from '@mui/material/styles' import { CacheProvider } from "@emotion/react" import createEmotionCache from "../lib/mui/createEmotionCache" import theme from '../config/material-ui/theme' const clientSideEmotionCache = createEmotionCache() export default function App({ Component, pageProps, emotionCache = clientSideEmotionCache // 参数名与_document.js传递的保持一致 }) { return ( <CacheProvider value={emotionCache}> <ThemeProvider theme={theme}> <Component {...pageProps} /> </ThemeProvider> </CacheProvider> ) }
原理说明
Next.js 13对服务端渲染流程做了调整,原有的originalRenderPage调用方式需修改为覆盖ctx.renderPage,确保渲染时使用自定义的emotion缓存,这样服务端才能正确提取页面所需的Critical CSS并注入到HTML中,避免客户端加载时的样式闪烁。
内容的提问来源于stack exchange,提问作者Laurent Dellere
相关产品推荐
相关产品推荐

