Next.Js 12 + MUI 5(Material UI) 새 튜토리얼

28885 단어 mui5nextjsnextjs12mui

추상적인


SSR 프레임워크에는 Next.js , Nuxt , Sveltekit 등 가장 가까운 프레임워크는 react 기반의 Next.js 일 것입니다.
본 보도에서는 Next.js 에 가장 반응이 좋은 컴포넌트 라이브러리 중 하나인 MUI을 적용하는 가장 최신 방법을 소개하고 싶다.

기존의 @mui/styles 패키지를 통해 적용하는 방법은 react 18 의 호환성 문제로 deprecated

MUI의 레거시 스타일링 솔루션: https://mui.com/system/styles/basics/

시작하기



원하는 프로젝트 폴더에 Next.js TypeScript 프로젝트를 생성합니다.


단말기


pnpm create next-app . --typescript  
MUI 관련 설치 패키지


단말기


pnpm add -S @emotion/cache @emotion/react @emotion/server @emotion/styled @mui/icons-material @mui/material


createEmotionCache 드디어 모듈인 emotionCache.tslib 폴더에 생성

메모


  • 클라이언트에서 <head/> 의 가장 최상단에 <meta> 태그를 생성하고 이를 insertionPoint 로 진단한다.
  • 이는 페이지 로드시 MUI style을 가장 먼저 로드하는 것을 확인
  • 이렇게 먼저 로드되는 경우 다른 스타일 솔루션들보다 높은 우선 순위를 가지게 되어 MUI 로 개발 가능한 이점을 가지게 된다.


  • lib/emotionCache.ts


    import createCache from '@emotion/cache';
    
    const isBrowser = typeof document !== 'undefined';
    
    const createEmotionCache = () => {
        let insertionPoint;
    
        if (isBrowser) {
            const emotionInsertionPoint = document.querySelector(
                'meta[name="emotion-insertion-point"]'
            ) as HTMLElement;
            insertionPoint = emotionInsertionPoint ?? undefined;
        }
    
        return createCache({ key: 'mui-style', insertionPoint });
    };
    
    export default createEmotionCache;
    


    lib 폴더에 theme.ts 도 생성

    메모


  • 더 글로벌 스타일을 적용하기 위해 theme.ts 생성기


  • lib/theme.ts


    import { createTheme } from '@mui/material/styles';
    import { indigo } from '@mui/material/colors';
    
    const theme = createTheme({
        palette: {
            primary: {
                main: indigo.A400,
            },
        },
    });
    
    export default theme;
    


    _app.tsx 파일을 다음과 같이 수정


    페이지/_app.tsx


    import * as React from 'react';
    import Head from 'next/head';
    import { ThemeProvider } from '@mui/material/styles';
    import { CacheProvider } from '@emotion/react';
    import CssBaseline from '@mui/material/CssBaseline';
    
    import theme from '../lib/theme';
    import createEmotionCache from '../lib/emotionCache';
    
    import type { NextPage } from 'next';
    import type { AppProps } from 'next/app';
    import type { EmotionCache } from '@emotion/react';
    
    type AppPropsWithCache = AppProps & {
        Component: NextPage;
        emotionCache?: EmotionCache;
    };
    
    const clientSideEmotionCache = createEmotionCache();
    
    const MyApp = ({
        Component,
        emotionCache = clientSideEmotionCache,
        pageProps,
    }: AppPropsWithCache) => {
        return (
            <CacheProvider value={emotionCache}>
                <Head>
                    <meta name='viewport' content='initial-scale=1, width=device-width' />
                </Head>
                <ThemeProvider theme={theme}>
                    <CssBaseline />
                    <Component {...pageProps} />
                </ThemeProvider>
            </CacheProvider>
        );
    };
    
    export default MyApp;
    


    _document.tsx 뒤 파일을 생성한 다음과 함께 작성

    메모


  • _Document.getInitialProps_app 이 대신 _document에 상속되고 static 으로 생성됨

  • _Document.getInitialProps = async (ctx: DocumentContext): Promise<DocumentInitialProps> => {...}
    

  • 캐시를 새로 생성하기 같은 감정 캐시를 SSR 요청에 사용하면 성능을 향상시키는 효과를 얻을 수 있다. (그러나 global side effect가 가능할 수 있는 시점이 되기도 한다.)
  • 여기서는 캐시마다 SSR 요청을 생성하기로 한다.

  • const cache = createEmotionCache();
    

  • styles fragmentapppage 의 포켓몬이 복제된다.

  • styles: [...React.Children.toArray(initialProps.styles), ...emotionStyleTags],
    

  • HTML 생성 방지를 방지하기 위해 다음 ③은 중요합니다.

  • 참고링크: https://github.com/mui/material-ui/issues/26561#issuecomment-855286153

    const emotionStyles = extractCriticalToChunks(initialProps.html);
    


    생성기




    서버
  • app.getInitialProps
  • page.getInitialProps
  • 문서.getInitialProps
  • 앱.렌더링
  • 페이지.렌더링
  • 문서.렌더링


  • 서버에러
  • 문서.getInitialProps
  • 앱.렌더링
  • 페이지.렌더링
  • 문서.렌더링


  • 친구
  • app.getInitialProps
  • page.getInitialProps
  • 앱.렌더링
  • 페이지.렌더링


  • 페이지/_document.tsx



    import * as React from 'react';
    import Document, { Html, Head, Main, NextScript } from 'next/document';
    import createEmotionServer from '@emotion/server/create-instance';
    import theme from '../lib/theme';
    import createEmotionCache from '../lib/emotionCache';
    
    import type { DocumentContext, DocumentInitialProps } from 'next/document';
    
    export default class _Document extends Document {
        render() {
            return (
                <Html lang='ko'>
                    <Head>
                        <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'
                        />
                        <meta name='emotion-insertion-point' content='' />
                        {this.props.styles}
                    </Head>
                    <body>
                        <Main />
                        <NextScript />
                    </body>
                </Html>
            );
        }
    }
    
    _Document.getInitialProps = async (ctx: DocumentContext): Promise<DocumentInitialProps> => {
        const originalRenderPage = ctx.renderPage;
    
        const cache = createEmotionCache();
        const { extractCriticalToChunks } = createEmotionServer(cache);
    
        ctx.renderPage = () =>
            originalRenderPage({
                enhanceApp: (App) =>
                    function EnhanceApp(props) {
                        return <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}
                // eslint-disable-next-line react/no-danger
                dangerouslySetInnerHTML={{ __html: style.css }}
            />
        ));
    
        return {
            ...initialProps,
            styles: [...React.Children.toArray(initialProps.styles), ...emotionStyleTags],
        };
    };
    


    index.tsx를 다음과 함께 작성


    페이지/index.tsx



    import { Button } from '@mui/material';
    
    import type { NextPage } from 'next';
    
    const Home: NextPage = () => {
        return (
            <main
                style={{
                    width: '100vw',
                    height: '100vh',
                    display: 'flex',
                    justifyContent: 'center',
                    alignItems: 'center',
                }}
            >
                <div>
                    <header>
                        <h1>MUI5 + Next.js 12</h1>
                    </header>
                    <section>
                        <Button variant={'contained'}>Hello MUI</Button>
                    </section>
                </div>
            </main>
        );
    };
    
    export default Home;
    




    시사




    ➕ Stackblitz 샘플




    결론



    본 포스팅에서는 MUI 5Next.Js 12 에 적용하는 최신 방법을 소개했습니다. (2022년 8월 기준)react 18 이면서 조합이 존재하는 방법보다 시야할 부분이 위장건이나 여전히 참조가 많은 조합을 선호하는 트렌트 입고는 가장 할 수 있는 SSR 프레임워크 + UI 라이브러리인 Next.Js + MUI는 킹 이용될 것이다.

    추천하는 React UI Framework 중 하나인 Mantine을 소개하면서 글을 마무리 짓고자 합니다.
    만타인: https://mantine.dev/

    좋은 웹페이지 즐겨찾기