Node.js ์ค์น
Next.js๋ฅผ ์ค์นํ๊ธฐ์ํด์๋ Node.js 18.17 or later ๋ฒ์ ์ด ํ์ํฉ๋๋ค.
Node.js๋ Javascript๋ก ์์ฑ๋ ํ๋ก๊ทธ๋จ์ ์ด์์ฒด์ ์์์ ์ผ๋ฐ ์ ํ๋ฆฌ์ผ์ด์
ํ๋ก๊ทธ๋จ์ฒ๋ผ ์คํ์์ผ์ฃผ๋ ๋ฐํ์์
๋๋ค. Next.js๋ฅผ ์ฌ์ฉํด๋ณด๊ธฐ ์ํด์ ์ค์นํด ๋ด
๋๋ค.
node.js ๊ณต์๋ฌธ์ https://nodejs.org/en
LTS ๋ค์ด๋ก๋ ํด๋ฆญํฉ๋๋ค. LTS๋ long-term supprot๋ก ์์ ํ ๋ ๋ฒ์ ์ด๋ผ๊ณ ๋ณด์๋ฉด๋ฉ๋๋ค.
๋ค์ด๋ก๋๊ฐ ์๋ฃ๋๋ฉด ์คํํ์ฌ Node.js๋ฅผ ์ค์นํฉ๋๋ค. ๋ชจ๋ Next๋ฅผ ๋๋ฌ์ ์ค์นํ์๋ฉด ๋ฉ๋๋ค. (ํน์ ์ค์น๊ฐ ์ ๋๋ก ๋์ง ์๋๋ค๋ฉด ๊ตฌ๊ธ์ Node.js์ค์น๋ฅผ ๊ฒ์ํ์๋ฉด ๋์์ด ๋๋ ๋ง์ ๊ธ๋ค์ด์์ต๋๋ค!)
์ค์น ์๋ฃ ํ ํฐ๋ฏธ๋์์ node -v๋ฅผ ์น๋ฉด ํ์ฌ ์ค์น๋ ๋ฒ์ ์ด ๋ํ๋๋ฉด ์ฑ๊ณต์ ๋๋ค.
ํ์ฌ ์ค์น๋ node ๋ฒ์ ์ 20.12.1์ ๋๋ค. node๋ nvm์ ํตํด ๋ฒ์ ๊ด๋ฆฌ๋ฅผ ํ ์ ์์ต๋๋ค.
์ด ํฌ์คํธ์์๋ nvm์ด์ผ๊ธฐ๋ ์๋ตํ๊ณ ๊ด๋ จ ํฌ์คํธ ๋งํฌ ์ฒจ๋ถํ๊ฒ ์ต๋๋ค. (nvm ์ค์น)์๊ฐ์ด ๋์ ๋ค๋ฉด ๋๋ฌด์ํค์์ Node.js์ ๋ํด์๋ ์ฝ์ด๋ณด์ธ์! (๋๋ฌด์ํค Node.js)
Next.js ์ค์น
Next.js๋ฅผ ์ค์นํ๊ธฐ ์์ ์ Next.js๋ฅผ ์ฐ๋์ง ์์๋ณด๊ฒ ์ต๋๋ค.
React ๊ณต์๋ฌธ์์ Strat a New React project๋ฅผ ๋ณด๋ฉด ํ๋ ์์ํฌ ์ฌ์ฉ์ ๊ถ์ฅํ๊ณ ์์ต๋๋ค. ์๋๋ ๊ณต์๋ฌธ์์์ ๋งํ๊ณ ์๋ ์ฅ์ ์ ์ ๋ฆฌํ์์ต๋๋ค.
Next.js๋ฟ ๋ง๋๋ผ Remix, Gatsby ๋ฑ ๋ค์ํ ํ๋ ์ ์ํฌ๊ฐ ์์ต๋๋ค. ์งํํ๊ณ ์ํ๋ ํ๋ก์ ํธ ํน์ฑ์ ๋ง๊ฒ ์ฌ์ฉํ๋ฉด ๋ฉ๋๋ค. (๊ฐ๋ฒผ์ด ํ๋ก์ ํธ๋ ์์ ๋ฆฌ์กํธ๋ฅผ ์ฌ์ฉํด๋ ๋ฌด๋ฐฉํฉ๋๋ค.)
๋ค์ ๋ณธ๋ก ์ผ๋ก ๋์์ Next.js ์ค์น ๋ฐฉ๋ฒ์ ๋ํด์ ์์๋ณด๊ฒ ์ต๋๋ค. ๋ด๊ฐ ์ค์นํ๊ณ ์ถ์ ๊ฒฝ๋ก์ ์ ๊ทผ ํ ํฐ๋ฏธ๋์ ์๋ ๋ช ๋ น์ด๋ฅผ ์คํํฉ๋๋ค.
npx create-next-app@latest
๋ช ๋ น์ด๋ฅผ ์คํํ๋ฉด ์๋์ฒ๋ผ ์ ๋ ฅ ๋ฐ๋ ์ฐฝ์ด ๋์ต๋๋ค.
- ์ํ๋ ํ๋ก์ ํธ์ด๋ฆ
- ํ์ ์คํฌ๋ฆฝํธ ์ฌ์ฉ์ฌ๋ถ
- ESlint ์ฌ์ฉ์ฌ๋ถ
- tailwind ์ฌ์ฉ์ฌ๋ถ
- src ํด๋ ์ฌ์ฉ์ฌ๋ถ
- app router์ฌ์ฉ์ฌ๋ถ
- import alias์ฌ์ฉ ์ฌ๋ถ
ํ๊ณ ์ํ๋ ํ๋ก์ ํธ ๊ธฐ์ ์คํ์ ๋ง๊ฒ ์ ํํ์๋ฉด ๋ฉ๋๋ค.์ค์น๊ฐ ์๋ฃ ํ vscode์์ ํ๋ก์ ํธ ํ์ผ์ ์ด์ด๋ณด๋ฉด npm์ผ๋ก ํจํค์ง๊ฐ ์ค์น๋์ด ์์ต๋๋ค.
(npm์ node.js์ ํจํค์ง(๋ ๋ฆฝ๋ ๋ชจ๋)์ ๊ฐ๋ฐํ๊ณ , ๋ฐฐํฌ, ๊ณต์ ํ๊ธฐ ์ํ ๊ด๋ฆฌ ํด์ ๋๋ค. ์์ธํ ๋ด์ฉ์ npm ๊ตฌ๊ธ๊ฒ์ GoGo)์ ๋ yarn ์ด๋ผ๋ ํจํค์ง ๋งค๋์ ๋ฅผ ์ฌ์ฉํ ๊ฒ์ด๊ธฐ ๋๋ฌธ์ yarn ์ ์ค์นํด์ค๋๋ค. ํฐ๋ฏธ๋์ ์๋ ๋ช ๋ น์ด๋ฅผ ์ ๋ ฅํฉ๋๋ค.
npm install --global yarn
yarn์ ์ค์น ํ ํฐ๋ฏธ๋์ yarn -v๋ก ๋ฒ์ ์ ํ์ธํฉ๋๋ค. ๋ฒ์ ์ด ๋์ค๋ฉด ์ค์น๊ฐ ์๋ฃ๋ ๊ฒ์ ๋๋ค.
๋ค์ ํ๋ก์ ํธ์์ ๊ฐ์ ์๋ node_modules์ pack-lock.json์ ์ง์ฐ๊ณ yarn install์ ์คํ ํฉ๋๋ค.
yarn ์ผ๋ก ํจํค์ง ์ค์น๊ฐ ๋ค์ ์๋ฃ ๋๋ฉด ์๋ ์ด๋ฏธ์ง ์ฒ๋ผ node_modules์ yarn.lock์ด ์์ฑ ๋ฉ๋๋ค.
์ด์ ํฐ๋ฏธ๋์์ yarn dev๋ก ํ๋ก์ ํธ๋ฅผ ์คํํ๋ฉด ์๋ ํ๋ฉด์ด localhost:3000์ ์คํ๋ฉ๋๋ค.
์ค์น ์๋ฃ!
MUI v5 ์ค์น
Next.js์ MUI๋ฅผ ์ ํ ํด๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค. ์ ํ ์ ์์ MUI๋? ์ ๊ตฌ๊ธ์ ๊ฒ์ํ๋ฉด..
MUI๋ Material Design ์์น์ ๊ธฐ๋ฐ์ผ๋ก ํ React ์ปดํฌ๋ํธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋๋ค. ๊ฐ๋ฐ์๊ฐ ๊ณ ํ์ง์ UI๋ฅผ ๋น ๋ฅด๊ฒ ๊ตฌ์ถํ ์ ์๋๋ก ๋ค์ํ ๋ฏธ๋ฆฌ ๋ง๋ค์ด์ง ์ปดํฌ๋ํธ๋ฅผ ์ ๊ณตํฉ๋๋ค. MUI๋ฅผ ์ฌ์ฉํ๋ฉด ์ ํ๋ฆฌ์ผ์ด์ ์ ์ผ๊ด์ฑ๊ณผ ์ ๊ทผ์ฑ์ ํฅ์์ํค๋ฉด์ ๊ฐ๋ฐ ์๊ฐ์ ํฌ๊ฒ ๋จ์ถ์ํฌ ์ ์์ต๋๋ค.
๋ผ๊ณ ํฉ๋๋ค. ใ ใ ์ ๋ ์ฒซ ํ์ฌ์์ styled-compoent๋ฅผ ์ฐ๋ค๊ฐ MUI๋ฅผ ์ฌ์ฉํ๊ฒ ๋์๋๋ฐ, ์ฒ์์๋ ์ปค์คํ ํ๋๋ฐ ๋๋ฌด ์ด๋ ค์์ ์ฐ๊ธฐ ์ซ๋ค๊ฐ ์ด์ ๋ MUI๋ง ์ฐ๊ฒ ๋์ต๋๋ค. ๋ญ ๊ทธ๋ ์ต๋๋ค.
๋ค์ ๋ณธ๋ก ์ผ๋ก ๋์์์ MUI๋ฅผ ์ค์นํฉ๋๋ค. ํฐ๋ฏธ๋์์ ์๋ ๋ช ๋ น์ด๋ฅผ ์ ๋ ฅํฉ๋๋ค.
yarn add @mui/material @emotion/react @emotion/styled
์ฃผ์ํ ์ ์ styledcompoent๋ server-rendered๋ฅผ ์ง์ํ์ง ์์ต๋๋ค. ๊ณต์๋ฌธ์์์ SSR ํ๋ก์ ํธ๋ ๊ฐ๋ ฅํ๊ฒ Emotion์ฐ๋ผ๊ณ ๊ถ์ฅํ๊ณ ์์ต๋๋ค. ๊ผญ emotion์ผ๋ก ์ค์นํฉ์๋ค.
์ค์น๋ฅผ ์๋ฃํ๊ณ ๊ณต์๋ฌธ์์์ Next.js๋ฅผ ์ฐพ์๋ณด๋ฉด ์๋ ํญ์ด ์์ต๋๋ค. ์ฌ๊ธฐ๋ฅผ ๋ณด๊ณ ์งํํด๋ ๋์ง๋ง v13 ๋ฒ์ ๊ธฐ์ค์ผ๋ก ์์ฑ๋์์ต๋๋ค. Next.js๋ ํ์ฌ v15๋ฅผ ๋ฐ๋ผ๋ณด๊ณ ์๋๋ฐ v13๊ธฐ์ค์ธ๊ฒ ์์ฃผ ๋ง์ ์๋ญ๋๋ค. ๋ค๋ฅธ๋ฐฉ๋ฒ์ ์ฐพ๊ฒ ์ต๋๋ค.
MUI๋ ์น์ ํ๊ฒ ๊ฐ ํ๋ ์์ํฌ๋ณ๋ก example project๋ฅผ ์ ๊ณตํด์ฃผ๊ณ ์์ต๋๋ค. ์ฌ๊ธฐ๊ฐ ์ ์ผ ์ต์ ํ๊ฐ ๋น ๋ฅด๋๋ผ๊ตฌ์. ์ผ๋จ Next.js App router + typescript๋ฅผ ํด๋ฆญํฉ๋๋ค. (js๋ฅผ ์ฌ์ฉํ๋ฉด js ํด๋ฆญ)
์๋ ์ฒ๋ผ ํ๋ก์ ํธ๊ฐ ๋์ต๋๋ค. ๋นจ๊ฐ์ ๋ค๋ชจ์ ์๋ ๋ช ๋ น์ด๋ฅผ ํฐ๋ฏธ๋์ ์คํํด์ ํด๋ก ํด ๋ด ์๋ค.
curl https://codeload.github.com/mui/material-ui/tar.gz/master | tar -xz --strip=2 material-ui-master/examples/material-ui-nextjs-ts cd material-ui-nextjs-ts
ํด๋ก ์ ์๋ฃ ํ ๋ด๊ฐ ์ค์นํ๊ณ ์๋ ํ๋ก์ ํธ์ ํ์ฌ ๋ฐ์ MUI example ํ๋ก์ ํธ๊ฐ ๋ญ๊ฐ ๋ค๋ฅธ์ง ๋น๊ตํด ๋ด ๋๋ค.
์ฌ์ค MUI example project๋ฅผ ๋ฐ๋ก ์จ๋๋์ง๋ง, ์ด๋ค ๋ถ๋ถ์ด ์ถ๊ฐ ๋์๋์ง ์์๋ณด๋ ๊ณผ์ ๋ ์ฌ๋ฐ์ต๋๋ค. ์ข ๋ ์ ์ดํดํ๊ฒ๊ฐ์ ๋๋์ ๋ฐ๋๋ค๋๊น? ๊ธฐ๋ถํ์ผ ์๋ ์์ต๋๋ค.
package.json๋ถํฐ ๋น๊ตํ๊ฒ ์ต๋๋ค.
์ง์ ์ค์น
// ์ง์ ์ค์น pack.json { "name": "nextv14", "version": "0.1.0", "private": true, "scripts": { "dev": "next dev", "build": "next build", "start": "next start", "lint": "next lint" }, "dependencies": { "@emotion/react": "^11.11.4", "@emotion/styled": "^11.11.5", "@mui/material": "^5.15.19", "next": "14.2.3", "react": "^18", "react-dom": "^18" }, "devDependencies": { "@types/node": "^20", "@types/react": "^18", "@types/react-dom": "^18", "eslint": "^8", "eslint-config-next": "14.2.3", "typescript": "^5" } }
MUI example
// mui example package.json { "name": "material-ui-nextjs-ts", "version": "5.0.0", "private": true, "scripts": { "dev": "next dev", "build": "next build", "start": "next start", "lint": "next lint", "post-update": "echo \"codesandbox preview only, need an update\" && pnpm update --latest" }, "dependencies": { "@emotion/cache": "latest", "@emotion/react": "latest", "@emotion/styled": "latest", "@mui/icons-material": "latest", "@mui/material": "latest", "@mui/material-nextjs": "latest", "next": "latest", "react": "latest", "react-dom": "latest" }, "devDependencies": { "@types/node": "latest", "@types/react": "latest", "@types/react-dom": "latest", "eslint": "latest", "eslint-config-next": "latest", "typescript": "latest" } }
package.json์ ๋น๊ตํด ๋ณด๋ฉด ๋ช๊ฐ์ง ์ฐจ์ด์ ์ด ๋ณด์ ๋๋ค. ์ฒซ๋ฒ์งธ๋ก example package.json์๋ ๋ฒ์ ์ด ๋ชจ๋ latest๋ก ์ค์ ๋์ด ์์ต๋๋ค. clone๋ฐ์ ๋ ๋ง๋ค ์ต์ ํ๋ ๋ฒ์ ์ผ๋ก ๋ฐ๊ฒํด์ฃผ๊ฒ ๋ค๋ ์๊ธฐ์ ๋๋ค. ํ์ง๋ง ์ค์ ์ ํ์ ์ ๋ ๊ฒ latest๋ก ํด๋์ผ๋ฉด ์ด๋ค ์ฌ๋ฐ๋ ์ผ์ด ์ผ์ด๋ ์ง ๋ชจ๋ฅด๋ ์ฃผ์ํด์ผํฉ๋๋ค. ๋๋ฒ์งธ๋ก๋ dependecies์ emotion/cache, mui/material-nextjs, mui/icons-material๊ฐ ๋ ์ค์น๋์ด์๋ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค. mui/icons ์ค์น์ํด๋ ๋ฌด๋ฐฉํ์ง๋ง ์ธ์ ๊ฐ ์ธ์ผ์ด ์๊ธฐ์ ๊ฐ์ด 3๊ฐ์ง ๋ชจ๋ ์ค์นํด ์ฃผ๊ฒ ์ต๋๋ค. ์๋ ๋ช ๋ น์ด๋ฅผ ํฐ๋ฏธ๋์ ์ ๋ ฅํฉ๋๋ค.
yarn add @mui/material-nextjs @emotion/cache @mui/icons-material
์ค์น๊ฐ ์๋ฃ๋์๋ค๋ฉด ์ด์ src/app ๊ฒฝ๋ก์์๋ layout.tsx๋ฅผ ๋ด์ผํฉ๋๋ค. Next.js layout ํ์ผ๋ก ์ํ๋ฅผ ์ ์งํ๊ฑฐ๋, ui๊ณต์ , no-rerender๋ฑ์ ํ ์ ์์ต๋๋ค. ์์ธํ ์ฌํญ์ ๋์ค์ ๋ค๋ฅธ ํฌ์คํธ๋ก ์ ๋ฆฌํ๊ธฐ๋กํ๊ณ ๊ณต์๋ฌธ์ ๋งํฌ๋จ๊ฒจ๋๊ฒ ์ต๋๋ค. (Next.js layout)
layout์ ๋น๊ตํด๋ณด๊ฒ ์ต๋๋ค.
์ง์ ์ค์น
import type { Metadata } from "next"; import { Inter } from "next/font/google"; import "./globals.css"; const inter = Inter({ subsets: ["latin"] }); export const metadata: Metadata = { title: "Create Next App", description: "Generated by create next app", }; export default function RootLayout({ children, }: Readonly<{ children: React.ReactNode; }>) { return ( <html lang="en"> <body className={inter.className}>{children}</body> </html> ); }
MUI example
import * as React from 'react'; import { AppRouterCacheProvider } from '@mui/material-nextjs/v14-appRouter'; import { ThemeProvider } from '@mui/material/styles'; import CssBaseline from '@mui/material/CssBaseline'; import theme from '@/theme'; export default function RootLayout(props: { children: React.ReactNode }) { return ( <html lang="en"> <body> <AppRouterCacheProvider options={{ enableCssLayer: true }}> <ThemeProvider theme={theme}> {/* CssBaseline kickstart an elegant, consistent, and simple baseline to build upon. */} <CssBaseline /> {props.children} </ThemeProvider> </AppRouterCacheProvider> </body> </html> ); }
MUI example ํ๋ก์ ํธ๋ฅผ ๋ณด๋ฉด bodyํ๊ทธ์๋ AppRouterCacheProvider๊ฐ children์ ๊ฐ์ธ๊ณ ์๊ณ ๊ทธ ์๋ ThemeProvider๊ฐ ๊ฐ์ธ์ ธ์์ต๋๋ค. AppRouterCacheProvider ๋ฒ์ ์ v14๋ก ๋์ด์๋ค์. AppRouterCacheProvider์ ์ญํ ์ ๊ณต์๋ฌธ์์ ๋์์์ต๋๋ค.
The
AppRouterCacheProvider
component is responsible for collecting the CSS generated by MUI System on the server, as Next.js is streaming chunks of the .html page to the client.While it's not required to use the
AppRouterCacheProvider
component, it's recommended to use it to ensure that the styles are appended to the<head>
and not rendering in the<body>
. See github.com/mui/material-ui/issues/26561#iss.. for why it's better.์์ฝํ์๋ฉด Next.js๋ streaming SSR๋ฐฉ์์ ์ฌ์ฉํฉ๋๋ค. ์ด๋ฅผ ๋ณด์ฅํ๊ธฐ์ํด AppRouterCacheProvider๋ฅผ ์ฌ์ฉํด์ผํ๋๊ฒ์ ๋๋ค. ApprouterCacheProvider ์ปดํฌ๋ํธ๋ฅผ ๋ค์ด๊ฐ๋ฉด EmotionCache๋ฅผ ์ฌ์ฉํ๊ณ ์๋ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค. ์๊น ์ถ๊ฐ๋ก ์ค์นํ EmotionCache๊ฐ ์ฌ๊ธฐ์ ์ฐ์ด๋ ๊ฒ์ ๋๋ค. ApprouterCacheProvider๋ฅผ ์ฌ์ฉํ๋ฉด headํ๊ทธ์ mui style์ ์ถ๊ฐํด์ฃผ๊ธฐ ๋๋ฌธ์ ์ฑ๋ฅ์ ์ด์ ๋ ์๋ค๊ณ ํฉ๋๋ค. options์์ฑ์ ๊ณต์๋ฌธ์ Go!
import * as React from 'react'; import { EmotionCache, Options as OptionsOfCreateCache } from '@emotion/cache'; export type AppRouterCacheProviderProps = { /** * These are the options passed to createCache() from 'import createCache from "@emotion/cache"'. */ options?: Partial<OptionsOfCreateCache> & { /** * If `true`, the generated styles are wrapped within `@layer mui`. * This is useful if you want to override the Material UI's generated styles with different styling solution, like Tailwind CSS, plain CSS etc. */ enableCssLayer?: boolean; }; /** * By default <CacheProvider /> from 'import { CacheProvider } from "@emotion/react"'. */ CacheProvider?: React.ElementType<{ value: EmotionCache; }>; children: React.ReactNode; }; /** * Emotion works OK without this provider but it's recommended to use this provider to improve performance. * Without it, Emotion will generate a new <style> tag during SSR for every component. * See https://github.com/mui/material-ui/issues/26561#issuecomment-855286153 for why it's a problem. */ export default function AppRouterCacheProvider(props: AppRouterCacheProviderProps): React.JSX.Element;
AppRouterCacheProvider์ ๋ํด ์์๋ดค์ผ๋ ThemeProvider์ CssBaseline์ ๋ํด์ ์์๋ณด๊ฒ ์ต๋๋ค. ThemeProvider MUI ๋์์ธ ์์คํ ์ ์ฌ์ฉํ๊ฑฐ๋ ์ปค์คํ ๋์์ธ ์์คํ ์ ์ฌ์ฉํ Themeํ์ผ์ ์ฃผ์ ํ๊ธฐ์ํด ์ฌ์ฉํฉ๋๋ค. props๋ก ์ ๋ฌ๋ themeํ์ผ์ ๋๋ค. ์ง์ ์ค์นํ๋ ํ๋ก์ ํธ์ themeํ์ผ์ ๋ง๋ค์ด ์ค์๋ค. ์ ๋ src์ shared/provider/mui ๊ฒฝ๋ก์ ์์ฑํ๊ฒ ์ต๋๋ค. ํด๋ ๊ตฌ์กฐ๋ ์ ํต์ ์ธ ํด๋๊ตฌ์กฐ ํน์ FSD๋ฅผ ์ฃผ๋ก ์ฌ์ฉํ๋๋ฐ ์ด๊ฑด ์๊ฐ๋๋ฉด ์ ๋ฆฌํ๊ฒ ์ต๋๋ค.
'use client'; import { Roboto } from 'next/font/google'; import { createTheme } from '@mui/material/styles'; const roboto = Roboto({ weight: ['300', '400', '500', '700'], subsets: ['latin'], display: 'swap', }); const theme = createTheme({ palette: { mode: 'light', }, typography: { fontFamily: roboto.style.fontFamily, }, components: { MuiAlert: { styleOverrides: { root: ({ ownerState }) => ({ ...(ownerState.severity === 'info' && { backgroundColor: '#60a5fa', }), }), }, }, }, }); export default theme;
CssBaseline์ html์ ๊ธฐ๋ณธ์ผ๋ก ์ ์ฉ๋ css๋ฅผ ๋ฆฌ์ ์ ํ ํด์ฃผ๋ ์ญํ ์ด๋ผ๊ณ ๋ณด์๋ฉด๋ฉ๋๋ค. (CssBaseline๊ณต์๋ฌธ์)
์ด์ ๋ค ์์๋ดค์ผ๋ layout.tsxํ์ผ์ ์ง์ ์ค์น ํ๋ก์ ํธ์ ๋ฐ๊ฟ๋ณด๊ฒ ์ต๋๋ค.
import * as React from "react"; import { AppRouterCacheProvider } from "@mui/material-nextjs/v14-appRouter"; import { ThemeProvider } from "@mui/material/styles"; import CssBaseline from "@mui/material/CssBaseline"; import theme from "@/shared/provider/mui/theme"; export default function RootLayout(props: { children: React.ReactNode }) { return ( <html lang="en"> <body> <AppRouterCacheProvider options={{ enableCssLayer: true }}> <ThemeProvider theme={theme}> {/* CssBaseline kickstart an elegant, consistent, and simple baseline to build upon. */} <CssBaseline /> {props.children} </ThemeProvider> </AppRouterCacheProvider> </body> </html> ); }
MUI๊ฐ ์ ์ ์ฉ๋๋์ง ํ์ธํ๊ธฐ์ํด app/page.tsx๋ ๋ณ๊ฒฝํด๋ณด๊ฒ ์ต๋๋ค.
import * as React from "react"; import Container from "@mui/material/Container"; import Typography from "@mui/material/Typography"; import Box from "@mui/material/Box"; import Link from "@mui/material/Link"; import NextLink from "next/link"; // import ProTip from '@/components/ProTip'; // import Copyright from '@/components/Copyright'; export default function Home() { return ( <Container maxWidth="lg"> <Box sx={{ my: 4, display: "flex", flexDirection: "column", justifyContent: "center", alignItems: "center", }} > <Typography variant="h4" component="h1" sx={{ mb: 2 }}> Material UI - Next.js App Router example in TypeScript </Typography> <Link href="/about" color="secondary" component={NextLink}> Go to the about page </Link> {/* <ProTip /> <Copyright /> */} </Box> </Container> ); }
yarn dev๋ก ์คํ ํ ํํ์ด์ง์ ์๋ ํ๋ฉด์ด ๋์ค๋ฉด MUI ์ ํ ์๋ฃ์ ๋๋ค.
์ฌ๊ธฐ๊น์ง ์ฝ๋๋ผ ๊ณ ์ํ์ จ์ต๋๋ค ใ ใ ๋ค์ ํฌ์คํธ๋ ํ๋ก์ ํธ ํด๋๊ตฌ์กฐ์ ๋ํด์ ์์ฑํด ๋ณด๊ฒ ์ต๋๋ค.