얼마 전에 진행했던 기업 사전 과제에서 Next.js에 css 프레임워크를 적용하라는 조건이 있어 mui를 적용하게 되었다.
react에서 개발할 때는 패키지 설치만 하면 간단하게 사용할 수 있었는데 Next.js에서는 추가적인 설정이 필요했다.
mui 설치
먼저 mui를 설치한다.
npm install @emotion/react @emotion/styled @mui/icons-material @mui/material @mui/styles
// or
yarn add @emotion/react @emotion/styled @mui/icons-material @mui/material @mui/styles
CssBaseline 설정
CssBaseline은 Next.js에서 mui를 쓰기 위해서 필수적인 것은 아니지만 어떤 브라우저에서 돌아가는지에 상관없이 일괄적인 스타일을 적용하기 위해서 추가해준다.
앱의 최상단에 넣어주면 알아서 normalize해준다.
pages/_app.tsx
import "../styles/globals.css";
import type { AppProps } from "next/app";
import { CssBaseline } from "@mui/material";
function MyApp({ Component, pageProps }: AppProps) {
return (
<>
<CssBaseline />
<Component {...pageProps} />
</>
);
}
export default MyApp;
document 세팅
_document는 서버사이드에 관여하는 로직 또는 static한 로직을 추가하는데 사용한다.
서버에서 받아온 html, css와 클라이언트가 렌더링한 html, css가 다르면 next에서 warning을 띄우기 때문에 서버단에서 mui를 지원함으로써 서버와 클라이언트간 간극을 맞춰줘야 한다.
pages/_document.tsx
import React from "react";
import Document, {
Html,
Head,
Main,
NextScript,
DocumentContext,
} from "next/document";
import { ServerStyleSheets } from "@mui/styles";
const MyDocument = () => {
return (
<Html>
<body>
<Head></Head>
<Main />
<NextScript />
</body>
</Html>
);
};
export default MyDocument;
MyDocument.getInitialProps = async (ctx: DocumentContext) => {
const materialSheets = new ServerStyleSheets();
const originalRenderPage = ctx.renderPage;
ctx.renderPage = () =>
originalRenderPage({
enhanceApp: (App) => (props) =>
materialSheets.collect(<App {...props} />),
});
const initialProps = await Document.getInitialProps(ctx);
return {
...initialProps,
styles: <>{initialProps.styles}</>,
};
};
+ Styled Components 적용하기
추가적으로 styled components를 적용하는 방법에 대해 알아보자. 먼저 styled components를 설치한다.
npm install --save-dev styled-components @types/styled-components babel-plugin-styled-components
// or
yarn add -D styled-components @types/styled-components babel-plugin-styled-components
.babelrc
먼저 바벨 파일을 아래와 같이 수정해주어야 한다.
이는 Next.js의 ssr과 연관이 있는데, ssr에 의해 styled-components 스타일이 적용되기 전에 화면이 렌더링되는 문제를 방지하기 위함이다.
{
"presets": ["next/babel"],
"plugins": [
[
"babel-plugin-styled-components",
{ "fileName": true, "displayName": true, "pure": true, "ssr": true }
]
]
}
pages/_document.tsx
import React from "react";
import Document, {
Html,
Head,
Main,
NextScript,
DocumentContext,
} from "next/document";
import { ServerStyleSheet } from "styled-components";
import { ServerStyleSheets } from "@mui/styles";
const MyDocument = () => {
return (
<Html>
<Head />
<body>
<Main />
<NextScript />
</body>
</Html>
);
};
export default MyDocument;
MyDocument.getInitialProps = async (ctx: DocumentContext) => {
const sheet = new ServerStyleSheet();
const materialSheets = new ServerStyleSheets();
const originalRenderPage = ctx.renderPage;
try {
ctx.renderPage = () =>
originalRenderPage({
enhanceApp: (App) => (props) =>
sheet.collectStyles(materialSheets.collect(<App {...props} />)),
});
const initialProps = await Document.getInitialProps(ctx);
return {
...initialProps,
styles: (
<>
{initialProps.styles}
{sheet.getStyleElement()}
</>
),
};
} finally {
sheet.seal();
}
};
기존의 코드에 ServerStyleSheet을 추가해주었다.
이를 통해 생성된 materialSheets로 지정한 컴포넌트(App)의 스타일 요소를 검색하고, 그 스타일을 style 태그로 추출한다. 그리고 이 결과물을 Document에 전달한다.
이렇게 되면 서버에서 렌더링이 되고, 소스 페이지에서도 스타일이 표시된다.
References
https://nextjs.org/docs/advanced-features/custom-document
https://github.com/mui/material-ui/tree/master/examples/nextjs
https://www.daleseo.com/material-ui-styles/
https://kyounghwan01.github.io/blog/React/next/mui/#세팅하기
https://kyounghwan01.github.io/blog/React/next/mui-styled/#프로젝트-세팅
'FE > Next.js' 카테고리의 다른 글
Next.js 시작하기 - (3) Pre-rendering, Data Fetching (0) | 2022.10.06 |
---|---|
Next.js 시작하기 - (2) CSS-in-JS, Custom App (2) | 2022.09.11 |
Next.js 시작하기 - (1) Project setting, Routing (0) | 2022.09.04 |