You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 19:25:19