최근에 Next 13.4 버전이 릴리즈 되면서 App 디렉토리 방식이 Stable 상태로 변경되었습니다.
-> https://nextjs.org/blog/next-13-4
새로운 프로젝트를 App 디렉토리 방식으로 초기세팅을 하던 중 겪은 문제에 대해서 정리하는 글입니다.
yarn add @mui/material @emotion/react @emotion/styled
아래 공식문서에 적혀있는 절차대로 진행하면 됩니다.
https://mui.com/material-ui/guides/interoperability/#tailwind-css
다만 공식문서에 있는 내용 그대로 진행했더니 아래 4번 포탈관련 설정이 적용이 안되어서
important 값을 "__next"가 아닌 "body"로 설정했습니다.
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
'./src/pages/**/*.{js,ts,jsx,tsx,mdx}',
'./src/components/**/*.{js,ts,jsx,tsx,mdx}',
'./src/app/**/*.{js,ts,jsx,tsx,mdx}',
],
important: 'body',
theme: {
extend: {},
},
plugins: [],
corePlugins: { // 추가
preflight: false,
},
}
layout.tsx에 바로 Provider를 생성할 경우 아래의 에러가 나올텐데
TypeError: createContext only works in Client Components. Add the "use client" directive at the top of the file to use it. Read more: https://nextjs.org/docs/messages/context-in-server-component
저는 provider들을 따로 관리하기 위한 클라이언트 컴포넌트를 따로 만들었습니다.
// layout.tsx
import React from 'react'
import '../styles/globals.css'
import { Inter } from 'next/font/google'
import Providers from './providers'
const inter = Inter({ subsets: ['latin'] })
export const metadata = {
title: 'Create Next App',
description: 'Generated by create next app',
}
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="ko">
<body className={inter.className}>
<div id="__next">
<Providers>
<main>{children}</main>
</Providers>
</div>
</body>
</html>
)
}
NextJS 13 App 디렉토리 방식부터 root div에 #__next가 사라졌습니다....
https://github.com/vercel/next.js/discussions/45541
이거 때문에 오래 해맸는데
직접 layout.tsx에서 #__next 로 감싸주면 해결됩니다
// providers.tsx
'use client'
import React from 'react'
import { CssBaseline, StyledEngineProvider } from '@mui/material'
const Providers = ({ children }: { children: React.ReactNode }) => {
return (
<>
<StyledEngineProvider injectFirst>
<CssBaseline />
{children}
</StyledEngineProvider>
</>
)
}
export default Providers
아래는 포탈관련해서 스타일이 안입혀지는 이슈에 해당하는 설정입니다.
// providers.tsx
'use client'
import React from 'react'
import { CssBaseline, StyledEngineProvider, ThemeProvider, createTheme } from '@mui/material'
const Providers = ({ children }: { children: React.ReactNode }) => {
let rootElement
if (typeof window !== 'undefined') {
rootElement = window.document.body
}
const theme = createTheme(
rootElement !== undefined
? {
components: {
MuiPopover: {
defaultProps: {
container: rootElement,
},
},
MuiPopper: {
defaultProps: {
container: rootElement,
},
},
MuiModal: {
defaultProps: {
container: rootElement,
},
},
},
}
: {},
)
return (
<>
<StyledEngineProvider injectFirst>
<ThemeProvider theme={theme}>
<CssBaseline />
{children}
</ThemeProvider>
</StyledEngineProvider>
</>
)
}
export default Providers
처음에는 단순히 클라이언트 컴포넌트라서
const rootElement = window.document.body
로 바로 접근하면 되는 줄 알았는데document is not defined
라는 에러가 나와서
검색해보니 클라이언트 컴포넌트도 서버측에서 prerender 하기 때문에 document 객체가 아직 존재하지 않아서 에러가 발생합니다.
해결방법 -> https://heokknkn.tistory.com/35
소스코드 : https://github.com/Taeyooooon/next-boilerplate-appdir
tailwind.config 에서 preflight false 옵션을 줘서 tailwind 에서 기존방식대로 border 스타일을 주면 말을 안듣는데 그럴때 global.css 에 아래 코드 추가해주면 됩니다.
상단에서 설정했던 mui의 CssBaseLine 가 reset css가 아닌 normalize css를 추구하기 때문이다.
*,
::before,
::after {
border-width: 0;
border-style: solid;
border-color: theme('borderColor.DEFAULT', currentColor);
}
https://tailwindcss.com/docs/preflight#border-styles-are-reset-globally
https://mui.com/material-ui/guides/interoperability/#tailwind-css