next는 SSR로 pre-rendering을 한다 즉 서버사이드에서 HTML+CSS를 브라우저에 전달 후 렌더링하고 다음 JS파일이 로드된다 그래서 CSS-IN-JS의 경우 스타일이 적용되지 않은 HTML파일이 렌더링되게 되는 문제가 있다
npm install styled-components
const nextConfig = {
compiler: {
styledComponents: true,
...
},
};
'use client'
import React, { useState } from 'react'
import { useServerInsertedHTML } from 'next/navigation'
import { ServerStyleSheet, StyleSheetManager } from 'styled-components'
export default function StyledComponentsRegistry({
children,
}: {
children: React.ReactNode
}) {
const [styledComponentsStyleSheet] = useState(() => new ServerStyleSheet())
useServerInsertedHTML(() => {
const styles = styledComponentsStyleSheet.getStyleElement()
styledComponentsStyleSheet.instance.clearTag()
return <>{styles}</>
})
if (typeof window !== 'undefined') return <>{children}</>
return (
<StyleSheetManager sheet={styledComponentsStyleSheet.instance}>
{children}
</StyleSheetManager>
)
}
<body>
<StyledComponentsRegistry>
{props.children}
</StyledComponentsRegistry>
</body>
적용해보면 아래와 같은 에러가 출력된다
Syntax error: "next/font" requires SWC although Babel is being used
due to a custom babel config being present.
babel보다는 SWC를 추천한다는 것 그래서 SWC 설정을 추가한다
설치
npm i -D @swc/plugin-styled-components
.swcrc 추가
{
"jsc": {
"experimental": {
"plugins": [
[
"@swc/plugin-styled-components",
{
"ssr": true
}
]
]
}
}
}
다른 Provider도 추가할 예정이므로 분류가 같은 것끼리 별도 파일로 관리하기로 한다
Global Style 추가
'use client'
import { createGlobalStyle } from 'styled-components'
const GlobalStyles = createGlobalStyle`
body{
background: beige;
}
`
export default GlobalStyles
theme 추가
const theme = {
colors: {
colorName1: '#aabbcc',
colorName2: 'hsla(50, 60%, 70%, 0.5)',
},
}
export default theme
theme Type 추가
//types/styled.d.ts
import 'styled-components'
import { theme } from '@/styles/theme'
type Theme = typeof theme
declare module 'styled-components' {
export interface DefaultTheme extends Theme {}
}
ThemeProvider 추가
'use client'
import { ThemeProvider } from 'styled-components'
import StyledComponentsRegistry from '@/styles/Registry'
import GlobalStyles from '@/styles/globalStyles'
import theme from '@/styles/theme'
export default function StylesProvider({
children,
}: {
children: React.ReactNode
}) {
return (
<StyledComponentsRegistry>
<GlobalStyles />
<ThemeProvider theme={theme}>{children}</ThemeProvider>
</StyledComponentsRegistry>
)
}