material-ui icon indicating copy to clipboard operation
material-ui copied to clipboard

[docs] [Mui v6] NextJS Pages Router with MUI v6 and Pigment CSS

Open Someone5328546 opened this issue 1 year ago • 3 comments

Related page

https://mui.com/material-ui/migration/migrating-to-pigment-css/

Kind of issue

Other

Issue description

Is it possible to use MUI v6 in its entirety, including Pigment CSS, with the NextJS pages router?

The Supported Frameworks section mentions only the App Router.

If Pigment CSS is not supported on the pages router, then could you please help with these questions?

  1. Should an app that uses MUI v5 and NextJS pages router avoid updating to MUI v6?
  2. If the app may update to v6 without issues, does anything change regarding the use of Emotion?

Below is how my app is using Emotion with MUI v5. It's based on a prior example from MUI's GitHub.

I see the current pages router example is using a much simpler approach of AppCacheProvider, which I don't think existed when I first put this implementation below together.

Should I switch to this implementation? It looks like I could completely stop using Emotion regardless of whether or not I upgrade to v6. However, if I upgrade to v6 and I'm on pages router still, would I have to keep using Emotion?

On a related note: are the examples on the GitHub current for v6 as well?

import createCache from '@emotion/cache'

const isBrowser = typeof document !== 'undefined'

// On the client side, Create a meta tag at the top of the <head> and set it as insertionPoint.
// This assures that MUI styles are loaded first.
// It allows developers to easily override MUI styles with other styling solutions, like CSS modules.
export default function createEmotionCache()
{
    let insertionPoint

    if (isBrowser)
    {
        const emotionInsertionPoint = document.querySelector<HTMLMetaElement>(
            'meta[name="emotion-insertion-point"]',
        )

        insertionPoint = emotionInsertionPoint ?? undefined
    }

    return createCache({ key: 'mui-style', insertionPoint })
}

And using it in _document.tsx:

import * as React from 'react'
import Document, {
  Html,
  Head,
  Main,
  NextScript,
  DocumentProps,
  DocumentContext,
} from 'next/document'

import { useTheme } from '@mui/material/styles'
import createEmotionServer from '@emotion/server/create-instance'
import { AppType } from 'next/app'
import createEmotionCache from '../src/createEmotionCache'
import { MyAppProps } from './_app'

interface MyDocumentProps extends DocumentProps
{
    emotionStyleTags: JSX.Element[]
}

export default function MyDocument({ emotionStyleTags }: MyDocumentProps)
{
    const theme = useTheme()
    return (
        <Html lang = 'en'>
            <Head>
                {/* PWA primary color */}
                <meta name = 'theme-color' content = {theme.palette.primary.main} />
                <link rel = 'shortcut icon' href = '/favicon.ico' />
                <meta name = 'emotion-insertion-point' content = '' />
                {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: DocumentContext) =>
{
    // 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

    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: React.ComponentType<React.ComponentProps<AppType> & MyAppProps>) =>
                function EnhanceApp(props) {
                return <App emotionCache={cache} {...props} />
                },
        })

    const initialProps = await Document.getInitialProps(ctx)
    // This is important. It prevents Emotion to render invalid HTML.
    // See https://github.com/mui/material-ui/issues/26561#issuecomment-855286153
    const emotionStyles = extractCriticalToChunks(initialProps.html)
    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,
    }
}

And finally in _app.tsx:

import { CacheProvider, EmotionCache  } from '@emotion/react'

export default function MyApp(props: MyAppProps) 
{
        return (
                <CacheProvider value = {emotionCache}>
                    <Head>
                    </Head>
                    <ThemeProvider theme = {theme}>
                    </ThemeProvider>
                </CacheProvider>
        )
}

Context

No response

Search keywords: nextjs pages router v6

Someone5328546 avatar Sep 08 '24 13:09 Someone5328546

As far as I remember, the pages router does not work with Material UI x Pigment CSS.

siriwatknp avatar Sep 10 '24 08:09 siriwatknp

Got it, thanks for the response. So in that case, if I were to update to v6 but stay with the pages router, would I keep my current Emotion implementation or switch to the new example using AppCacheProvider? Or is there no practical difference?

Someone5328546 avatar Sep 10 '24 14:09 Someone5328546

Got it, thanks for the response. So in that case, if I were to update to v6 but stay with the pages router, would I keep my current Emotion implementation or switch to the new example using AppCacheProvider? Or is there no practical difference?

Yes you can upgrade to v6 as Emotion is still the main engine for Material UI v6. AppCacheProvider is a quick integration for using with Next.js pages router with Emotion.

siriwatknp avatar Sep 12 '24 12:09 siriwatknp

Since the issue is missing key information and has been inactive for 7 days, it has been automatically closed. If you wish to see the issue reopened, please provide the missing information.

github-actions[bot] avatar Oct 29 '24 12:10 github-actions[bot]

@siriwatknp Hi, I think my app would benefit from Pigment CSS. I'm using MUI v5 but I'm still on NextJS Pages Router. I see that in you answer you've written "as far as I remember". Are you certain now and is there no way to use PigmentCSS with the Pages Router

YovchoKalev avatar Jan 06 '25 10:01 YovchoKalev

I would like to know this too, My app uses pages router, is there a way to use Pigment css

SC0d3r avatar Jan 28 '25 01:01 SC0d3r