π Next.js β€οΈ styled-component
Next.js μ Styled Component λ₯Ό ν¨κ» μ¬μ©ν λ μ μ ν μ€μ μ νμ§ μμΌλ©΄
SSR μμ FOUC (Flash of Unstyled Content) νμμ΄ λ°μνκ² λ©λλ€.
π€ FOUC?
νμ΄μ§μ μ€νμΌμνΈ μ λ³΄κ° λ‘λ μμ μ ν¬ν¨λμ§ μμ
μ μ μ€νμΌμ΄ μ μ©λμ§ μμ νμ΄μ§κ° λνλλ νμμ λλ€.
π FOUC μμΈ νμ νκΈ°
Next.js SSR (Pre Rendering)
Server-side Rendering κ³Ό Static Generation λͺ¨λ Pre-rendering λ°©μμ΄λ©°
νμν data fetching κ³Ό HTML λ λλ§μ΄ client μκ² λ³΄λ΄μ§κΈ° μ μ μ΄λ―Έ μνλ©λλ€.
μ΄λ₯Ό ν΅ν΄ client λ non-interactive ν νμ΄μ§λ₯Ό λΉ λ₯Έ μκ°μ μ λ¬ λ°μ μ μκ³ ,
μ»΄ν¬λνΈμ νμν μ΄λ²€νΈ 리μ€λμ κ°μ interactive μμ±λ€μ λ³λμ λ²λ€λ‘ μ λ¬λ°μ
client λ¨μμ hydration μ΄ μ΄λ£¨μ΄μ§ λ€ μ°λ¦¬κ° μνΈμμ©νλ μΉμ±μ΄ λ©λλ€.
css-in-js
μ΄ λλ¬Έμ ssr μμ styled component μ κ°μ css-in-js λ₯Ό μ¬μ©ν λ λ¬Έμ κ° λ°μν©λλ€.
hydrate κ³Όμ μμ λ€μ΄λ‘λ λ°μ JS λ₯Ό ν΅ν΄ μ§μ λ μ€νμΌ μ λ³΄κ° μκΈ°κΈ° λλ¬Έμ
νμ΄μ§ λ‘λμ μ κΉ μ€νμΌμ΄ λλ½λ νλ©΄μ΄ λ³΄μ¬μ§κ² λ©λλ€.
μ΄λ μ¬μ©μμκ² μ’μ§ μμ UX κ²½νμ μ 곡ν μ μλ μμλ‘ λ³Ό μ μμ΅λλ€.
π Styled Component SSR μ€μ
λ€ννλ styled-component λ SSR λ₯Ό μ§μνλ©° μ΄ λ¬Έμ λ₯Ό ν΄κ²°ν μ μμ΅λλ€.
Next.js λ²μ μ λ°λΌ swc νΉμ babel μ¬μ© μ¬λΆκ° λ€λ₯΄κΈ° λλ¬Έμ λμ λ°©λ²μ΄ λ€λ¦ λλ€.
1οΈβ£ Next.js v11 μ΄ν
μμ μ μΈ ssr λ₯Ό μν΄ babel-plugin-styled-components νλ¬κ·ΈμΈ μ€μ μ΄ νμν©λλ€.
ν΄λΉ νλ¬κ·ΈμΈμ ν΅ν΄ κ°κ°μ styled-component μ checksum λΆμΌμΉλ₯Ό λ°©μ§ν©λλ€.
// .babelrc
{
"plugins": ["babel-plugin-styled-components"]
}
μ΄ν custom Document λ₯Ό μ μν λ€, getInitialProps μμ κ°κ°μ νμ΄μ§μ λ€μ΄κ° <head> νκ·Έμ
SSR μμ λ°μλμ΄μΌ ν styled-component μ 보λ₯Ό μ£Όμ ν©λλ€.
// pages/_document.js
import Document, { DocumentContext, DocumentInitialProps } from 'next/document'
import { ServerStyleSheet } from 'styled-components'
export default class MyDocument extends Document {
static async getInitialProps(
ctx: DocumentContext
): Promise<DocumentInitialProps> {
const sheet = new ServerStyleSheet()
const originalRenderPage = ctx.renderPage
try {
ctx.renderPage = () =>
originalRenderPage({
enhanceApp: (App) => (props) =>
sheet.collectStyles(<App {...props} />),
})
const initialProps = await Document.getInitialProps(ctx)
return {
...initialProps,
styles: (
<>
{initialProps.styles}
{sheet.getStyleElement()}
</>
),
}
} finally {
sheet.seal()
}
}
render() { /** */ }
}
next.js/_document.tsx at canary · vercel/next.js
2οΈβ£ Next.js v12 μ΄μ
Next.js v12 μ΄μλΆν°λ swc λ₯Ό ν΅ν΄ JS λ²λ€μ μ»΄νμΌν©λλ€.
μ΄ κ²½μ° λ³λμ babel μ€μ μμ΄ μ체μ μΌλ‘ styled-component μ ssr μ€μ μ΄ κ°λ₯ν©λλ€.
// next.config.js
const nextConfig = {
compiler: {
styledComponents: true,
},
}
module.exports = nextConfig
μ΄ν Next.js v11 κ³Ό λμΌνκ² _document.js μμ custom Document λ₯Ό μ μνκ³
getInitialProps λ΄μμ μ€νμΌ μ 보λ₯Ό μ£Όμ ν©λλ€.
// pages/_document.js
import Document, { DocumentContext } from 'next/document'
import { ServerStyleSheet } from 'styled-components'
export default class MyDocument extends Document {
static async getInitialProps(ctx: DocumentContext) {
const sheet = new ServerStyleSheet()
const originalRenderPage = ctx.renderPage
try {
ctx.renderPage = () =>
originalRenderPage({
enhanceApp: (App) => (props) =>
sheet.collectStyles(<App {...props} />),
})
const initialProps = await Document.getInitialProps(ctx)
return {
...initialProps,
styles: [initialProps.styles, sheet.getStyleElement()],
}
} finally {
sheet.seal()
}
}
render() { /** */ }
}
next.js/_document.tsx at canary · vercel/next.js
λ³΄λ€ μμΈν λ΄μ©μ styled-component λ¬Έμλ₯Ό μ°Έκ³ νλ©΄ λ©λλ€.
styled-components: Advanced Usage
π μ°Έκ³ μλ£
'π¨βπ» web.dev > fe' μΉ΄ν κ³ λ¦¬μ λ€λ₯Έ κΈ
React Framer Motion νΊμ보기 (0) | 2023.03.27 |
---|---|
νλ‘ νΈμλ E2E ν μ€ν (with Cypress) (2) | 2023.03.19 |
AWS SDK λ‘ s3 νμΌ μ¬μ΄μ¦ μ‘°ννκΈ° (0) | 2022.11.26 |
React μ΄λ²€νΈ μ²λ¦¬λ°©μκ³Ό SyntheticEvent (0) | 2022.10.17 |
File API λ₯Ό μ΄μ©ν Input μ»΄ν¬λνΈ λ§λ€κΈ° (2) | 2022.08.13 |
π¬ λκΈ