Getting Started (์‹œ์ž‘ํ•˜๊ธฐ)

์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋ฃจํŠธ ๊ฒฝ๋กœ์— pages์™€ public ๋””๋ ‰ํ† ๋ฆฌ๊ฐ€ ์ƒ์„ฑ๋œ๋‹ค.

  • pages: ๋””๋ ‰ํ† ๋ฆฌ ๋‚ด๋ถ€์˜ ํŒŒ์ผ ๋ช…์€ ๋ผ์šฐํ„ฐ์™€ ์—ฐ๊ฒฐ๋œ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, pages/about.js๋Š” /about ๊ณผ ๋งคํ•‘๋œ๋‹ค.
  • public: ์ด๋ฏธ์ง€, ํฐํŠธ ๋“ฑ ์ •์  ๋ฆฌ์†Œ์Šค๋ฅผ ์ €์žฅํ•œ๋‹ค. public ํด๋” ์•ˆ ํŒŒ์ผ๋“ค์€ base URL(/)์œผ๋กœ ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰๋˜๊ธฐ ์ „์— ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ๋‹ค.

Next.js๋Š” ํŽ˜์ด์ง€ ๊ฐœ๋…์„ ์ค‘์‹ฌ์œผ๋กœ ๋งŒ๋“ค์–ด์กŒ๋‹ค. ํŽ˜์ด์ง€๋ž€ pages ๋””๋ ‰ํ† ๋ฆฌ ๋‚ด๋ถ€์˜ .js, .jsx, .ts, or .tsx ํƒ€์ž…์˜ ๋ฆฌ์•กํŠธ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋งํ•œ๋‹ค. ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ํŒŒ์ผ ์ด๋ฆ„์„ ํ†ตํ•ด dynamic route ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

pages ๋””๋ ‰ํ† ๋ฆฌ ์•ˆ์˜ index.js ํŒŒ์ผ์€ ์‹œ์ž‘์„ ์œ„ํ•œ ํŒŒ์ผ์ด๋‹ค. ์‚ฌ์šฉ์ž๊ฐ€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋ฐฉ๋ฌธํ–ˆ์„ ๋•Œ ๋ Œ๋”๋ง ๋˜๋Š” ํŽ˜์ด์ง€์ด๋‹ค.

์ง€๊ธˆ๊นŒ์ง€ ์šฐ๋ฆฌ๋Š”:

Basic Features (๊ธฐ๋ณธ์ ์ธ ๊ธฐ๋Šฅ)

Pages

pages/ ๋””๋ ‰ํ† ๋ฆฌ์˜ ๊ฐ ํŽ˜์ด์ง€๋Š” ํŒŒ์ผ ์ด๋ฆ„์„ ๊ธฐ๋ฐ˜์œผ๋กœ ๋ผ์šฐํ„ฐ์™€ ์—ฐ๊ฒฐ๋œ๋‹ค.

์˜ˆ: pages/about.js ๋ฆฌ์•กํŠธ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋งŒ๋“ค์—ˆ๋‹ค๋ฉด ๊ทธ๊ฒƒ์€ /about์œผ๋กœ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค.

Pages with Dynamic Routes

Next.js๋Š” ๋™์  ๋ผ์šฐํŒ… ํŽ˜์ด์ง€๋ฅผ ์ง€์›ํ•œ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, pages/posts/[id].js ํŒŒ์ผ์„ ๋งŒ๋“ค์—ˆ๋‹ค๋ฉด, ๊ทธ๊ฒƒ์€ posts/1, posts/2 ๋“ฑ์œผ๋กœ ์ ‘๊ทผ์ด ๊ฐ€๋Šฅํ•  ์ˆ˜ ์žˆ๋‹ค.

Pre-rendering

๊ธฐ๋ณธ์ ์œผ๋กœ, Next.js๋Š” ๋ชจ๋“  ํŽ˜์ด์ง€๋ฅผ ๋ฏธ๋ฆฌ ๋ Œ๋”๋งํ•œ๋‹ค. ์ด๊ฒƒ์€ Next.js๋Š” client-side์—์„œ ๋ชจ๋“  ๊ฒƒ์„ ์ˆ˜ํ–‰ํ•˜๋Š”๊ฒŒ ์•„๋‹ˆ๋ผ ๋ฏธ๋ฆฌ ๊ฐ ํŽ˜์ด์ง€์˜ HTML์„ ์ƒ์„ฑํ•œ๋‹ค๋Š” ์˜๋ฏธ์ด๋‹ค. Pre-rendering์€ ์„ฑ๋Šฅ๊ณผ SEO ์ธก๋ฉด์—์„œ ๋” ๋‚˜์€ ๊ฒฐ๊ณผ๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๋‹ค.

์ƒ์„ฑ๋œ ๊ฐ HTML์€ ํ•ด๋‹น ํŽ˜์ด์ง€์— ํ•„์š”ํ•œ ์ตœ์†Œํ•œ์˜ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ฝ”๋“œ์™€ ์—ฐ๊ด€๋˜์–ด ์žˆ๋‹ค. ๋ธŒ๋ผ์šฐ์ €๋กœ๋ถ€ํ„ฐ ํ•ด๋‹น ํŽ˜์ด์ง€๋ฅผ ์š”์ฒญ ๋ฐ›์•˜์„ ๋•Œ, ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰๋˜๋ฉด์„œ ํŽ˜์ด์ง€๋ฅผ ์™„์ „ํžˆ ์ƒํ˜ธ์ž‘์šฉํ•˜๊ฒŒ ๋งŒ๋“ ๋‹ค. (์ด ํ”„๋กœ์„ธ์Šค๋ฅผ hydration์ด๋ผ๊ณ  ํ•จ.)

Pre-rendering์˜ ๋‘๊ฐ€์ง€ ํ˜•ํƒœ

Next.js๋Š” pre-rendering์˜ ๋‘๊ฐ€์ง€ ํ˜•ํƒœ๋ฅผ ๊ฐ–๊ณ ์žˆ๋‹ค: Static Generation๊ณผ Server-side Rendering. ์ด๊ฒƒ์€ ์–ธ์ œ HTML์„ ์ƒ์„ฑํ•˜๋Š”์ง€์— ์ฐจ์ด๊ฐ€ ์žˆ๋‹ค.

  • Static Generation (์ถ”์ฒœ): HTML์ด ๋นŒ๋“œ๋  ๋•Œ ์ƒ์„ฑ๋˜์–ด ๊ฐ ์š”์ฒญ์— ์˜ํ•ด ์žฌ์‚ฌ์šฉ๋œ๋‹ค.
  • Server-side Rendering: HTML์ด ๊ฐ ์š”์ฒญ ๋•Œ ์ƒ์„ฑ๋œ๋‹ค.

์ค‘์š”ํ•œ๊ฑด, Next.js๋Š” ๊ฐ ํŽ˜์ด์ง€๋ฅผ ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉํ• ์ง€์— ๋”ฐ๋ผ pre-rendering ์„ ์„ ํƒ์ ์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ๋‹ค์ˆ˜์˜ ํŽ˜์ด์ง€๋ฅผ ์œ„ํ•œ Static Generation๊ณผ ๊ทธ ์™ธ์˜ ํŽ˜์ด์ง€๋“ค์„ ์œ„ํ•œ Server-side Rendering์„ ๋™์‹œ์— ์‚ฌ์šฉํ•˜๋Š” โ€œhybridโ€ Next.js ์•ฑ์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.

์„ฑ๋Šฅ์ƒ์˜ ์ด์œ ๋กœ Server-side Rendering ๋ณด๋‹ค๋Š” Static Generation ์‚ฌ์šฉ์„ ์ถ”์ฒœํ•œ๋‹ค. ์ •์ ์œผ๋กœ ์ƒ์„ฑ๋œ ํŽ˜์ด์ง€๋Š” ๋ณ„๋„์˜ ๊ตฌ์„ฑ ์—†์ด CDN์œผ๋กœ๋ถ€ํ„ฐ ์บ์‹ฑ๋˜์–ด ์„ฑ๋Šฅ์„ ํ–ฅ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๊ฒฝ์šฐ์— ๋”ฐ๋ผ Server-side Rendering๋งŒ ์‚ฌ์šฉํ•ด์•ผํ•  ์ˆ˜ ์žˆ๋‹ค.

Static Generation ๋˜๋Š” Server-side Rendering๊ณผ ํ•จ๊ป˜ Client-side data fetching ๋˜ํ•œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ๋ฌด์กฐ๊ฑด ํด๋ผ์ด์–ธํŠธ ์ธก ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ ๋ Œ๋”๋ง ๋˜์–ด์•ผํ•˜๋Š” ํŽ˜์ด์ง€์˜ ๊ฒฝ์šฐ๋ฅผ ๋œปํ•œ๋‹ค.

Static Generation

Static Generation์„ ์‚ฌ์šฉํ•˜๋Š” ํŽ˜์ด์ง€๋ผ๋ฉด, ํ•ด๋‹น ํŽ˜์ด์ง€์˜ HTML์€ ๋นŒ๋“œ ์‹œ์— ์ƒ์„ฑ๋œ๋‹ค. next build ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ–ˆ์„ ๋•Œ HTML์ด ์ƒ์„ฑ๋œ๋‹ค๋Š” ๋œป์ด๋‹ค. HTML์€ ๊ฐ ์š”์ฒญ ์‹œ์— ์žฌ์‚ฌ์šฉ๋œ๋‹ค. ์ด๊ฒƒ ๋˜ํ•œ CDN์„ ํ†ตํ•ด ์บ์‹ฑ๋œ๋‹ค.

Next.js์—์„œ๋Š” ๋ฐ์ดํ„ฐ์˜ ์œ ๋ฌด์™€ ์ƒ๊ด€์—†์ด ์ •์ ์œผ๋กœ ํŽ˜์ด์ง€๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.

Static Generation without data

๊ธฐ๋ณธ์ ์œผ๋กœ, Next.js๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค์ง€ ์•Š๊ณ  Static Generation์„ ์‚ฌ์šฉํ•˜์—ฌ pre-render ๋œ๋‹ค.

function About() {
    return <div>About</div>
}

export default About

์ด ํŽ˜์ด์ง€๋Š” ์‚ฌ์ „์— ๋ Œ๋”๋ง ๋  ๋•Œ ์™ธ๋ถ€ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ฌ ํ•„์š”๊ฐ€ ์—†๋‹ค. ์ด๋Ÿฌํ•œ ๊ฒฝ์šฐ Next.js๋Š” HTML ํŽ˜์ด์ง€๋ฅผ ๋นŒ๋“œ ์‹œ์— ์ƒ์„ฑํ•œ๋‹ค.

Static Generation with data

๋ช‡๋ช‡ ํŽ˜์ด์ง€๋“ค์€ pre-rendering์„ ์œ„ํ•œ ์™ธ๋ถ€ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์™€์•ผํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ๋‹ค. ์ด๋Ÿฌํ•œ ๊ฒฝ์šฐ Next.js์—์„œ ์ œ๊ณต๋˜๋Š” ๋‘๊ฐ€์ง€ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค:

  1. ์™ธ๋ถ€ ๋ฐ์ดํ„ฐ๊ฐ€ ํŽ˜์ด์ง€ ๋‚ด์šฉ๊ณผ ์˜์กด๋˜๋Š” ๊ฒฝ์šฐ: getStaticProps
  2. ์™ธ๋ถ€ ๋ฐ์ดํ„ฐ๊ฐ€ ๊ฒฝ๋กœ์™€ ์˜์กด๋˜๋Š” ๊ฒฝ์šฐ: getStaticPaths (์ผ๋ฐ˜์ ์œผ๋กœ getStaticProps์™€ ํ•จ๊ป˜ ์‚ฌ์šฉ)

์˜ˆ: ๋ธ”๋กœ๊ทธ์—์„œ ๊ธ€ ๋ชฉ๋ก์„ ๊ฐ€์ ธ์˜ค๋Š” ๊ฒฝ์šฐ

์‚ฌ์ „ ๋ Œ๋” ์‹œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๊ธฐ ์œ„ํ•ด Next.js๋Š” ๋™์ผํ•œ ํŒŒ์ผ์—์„œ getStaticProps ๋น„๋™๊ธฐ ํ•จ์ˆ˜๋ฅผ export ํ•œ๋‹ค. ์ด ํ•จ์ˆ˜๋Š” ๋นŒ๋“œ ํƒ€์ž„ ๋•Œ ํ˜ธ์ถœ๋˜๋ฉฐ ์‚ฌ์ „ ๋ Œ๋”๋ง ์‹œ ๊ฐ€์ ธ์˜จ ๋ฐ์ดํ„ฐ๋ฅผ page์˜ props๋กœ ์ „๋‹ฌํ•œ๋‹ค.

export default function Blog({ posts }) {
    
}

export async function getStaticProps() {
    const res = await fetch('https://.../posts');
    const posts = await res.json();
    
    return {
        props: {
            posts,
        },
    }
}

getStaticPaths()

export async function getStaticPaths() {
    const res = await fetch('https://.../posts');
    const posts = await res.json();
    
    const paths = posts.map(post => ({
        params: { id: posts.id },
    }));
    
    return { paths, fallback: false };
}

์–ธ์ œ Static Generation์„ ์‚ฌ์šฉํ•ด์•ผํ• ๊นŒ?

์–ธ์ œ๋“  ๊ฐ€๋Šฅํ•˜๋‹ค๋ฉด Static Generation(๋ฐ์ดํ„ฐ๊ฐ€ ์žˆ๋“  ์—†๋“ ) ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ๊ถŒ์žฅํ•œ๋‹ค. ์™œ๋ƒํ•˜๋ฉด ํŽ˜์ด์ง€๋Š” ํ•œ๋ฒˆ ๋นŒ๋“œ๋˜๊ณ  CDN์œผ๋กœ๋ถ€ํ„ฐ ์ œ๊ณต๋˜๊ธฐ ๋•Œ๋ฌธ์— ๋ชจ๋“  ์š”์ฒญ์„ ์„œ๋ฒ„๊ฐ€ ๋ Œ๋”๋ง ํ•ด์ฃผ๋Š” ๊ฒƒ๋ณด๋‹ค ๋”์šฑ ๋น ๋ฅด๋‹ค.

Server-side Rendering

Server-side Rendering์„ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” getServerSideProps ๋น„๋™๊ธฐ ํ•จ์ˆ˜๋ฅผ export ํ•ด์•ผ ํ•œ๋‹ค. ์ด ํ•จ์ˆ˜๋Š” ๋งค ์š”์ฒญ๋งˆ๋‹ค ์„œ๋ฒ„๋กœ๋ถ€ํ„ฐ ํ˜ธ์ถœ๋œ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด, ํŽ˜์ด์ง€์—์„œ ์ž์ฃผ ์—…๋ฐ์ดํŠธ ๋˜๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ๋ Œ๋”๋งํ•ด์•ผ ํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด๋ณด๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด Page์— ์ „๋‹ฌํ•˜๋Š” getServerSideProps๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.

export default function Page({ data }) {
    
}

export async function getServerSideProps() {
    const res = await fetch('https://.../data');
    const data = await res.json();
    
    return { props: { data }};
}

๋ณด๋Š” ๊ฒƒ๊ณผ ๊ฐ™์ด getServerSideProps๋Š” getStaticProps์™€ ๋น„์Šทํ•˜๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋‹ค๋ฅธ ์ ์€ getServerSideProps๋Š” ๋นŒ๋“œ ๋•Œ๋งŒ ํ˜ธ์ถœ๋˜๋Š”๊ฒŒ ์•„๋‹ˆ๋ผ ๋งค ์š”์ฒญ๋งˆ๋‹ค ํ˜ธ์ถœ๋œ๋‹ค๋Š” ์ ์ด๋‹ค.

Data Fetching Overview (๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ ๊ฐœ์š”)

Next.js์—์„œ ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ๋”ฐ๋ผ ๋‹ค์–‘ํ•œ ๋ฐฉ๋ฒ•์œผ๋กœ ์ฝ˜ํ…์ธ ๋ฅผ ๋ Œ๋”๋งํ•  ์ˆ˜ ์žˆ๋‹ค. Server-side Rendering ๋˜๋Š” Static Generation ๊ณผ ๊ฐ™์€ pre-rendering์„ ํฌํ•จํ•˜๊ณ  ๋Ÿฐํƒ€์ž„ ์‹œ ์ˆ˜์ • ๋˜๋Š” ์ฝ˜ํ…์ธ  ์ƒ์„ฑ์„ ์œ„ํ•œ Incremental Static Regeneration์ด ์žˆ๋‹ค.

getServerSideProps

๋งŒ์•ฝ ํŽ˜์ด์ง€๋กœ๋ถ€ํ„ฐ getServerSideProps(Server-Side Rendering) ๊ฐ€ ํ˜ธ์ถœ๋œ๋‹ค๋ฉด Next.js๋Š” getServerSideProps์—์„œ ๋ฐ˜ํ™˜๋œ ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ ์š”์ฒญ์„ ์œ„ํ•œ ํŽ˜์ด์ง€๋ฅผ ๋ฏธ๋ฆฌ ๋ Œ๋”๋งํ•œ๋‹ค.

getServerSideProps๋Š” ์˜ค์ง ํŽ˜์ด์ง€์—์„œ๋งŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. page๊ฐ€ ์•„๋‹Œ ํŒŒ์ผ์—์„œ๋Š” ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค.

์–ธ์ œ getServerSideProps๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ• ๊นŒ

์š”์ฒญ ์‹œ ๋ฐ˜๋“œ์‹œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์™€์•ผํ•˜๋Š” ํŽ˜์ด์ง€๋ฅผ ๋ Œ๋”๋งํ•˜๋Š” ๊ฒฝ์šฐ์—๋งŒ getServerSideProps ๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค. getServerSideProps๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ํŽ˜์ด์ง€๋Š” ์š”์ฒญ ์‹œ ์„œ๋ฒ„ ์ธก์—์„œ ๋ Œ๋”๋ง๋˜๋ฉฐ cache-control ํ—ค๋”๊ฐ€ ๊ตฌ์„ฑ๋œ ๊ฒฝ์šฐ์—๋งŒ ์บ์‹ฑ๋œ๋‹ค.

๋งŒ์•ฝ ์š”์ฒญ ๋™์•ˆ์— ๋ฐ์ดํ„ฐ๋ฅผ ๋ Œ๋”๋งํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค๋ฉด, ํด๋ผ์ด์–ธํŠธ ์‚ฌ์ด๋“œ ๋˜๋Š” getStaticProps ๋ฅผ ํ†ตํ•ด ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๊ฒƒ์„ ๊ณ ๋ คํ•ด์•ผ ํ•œ๋‹ค.

getServerSideProps or API Routes

์„œ๋ฒ„์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๊ฒƒ์„ ์›ํ•œ๋‹ค๋ฉด API Route์— ๋„๋‹ฌํ•œ ๋‹ค์Œ getServerSideProps์—์„œ ํ•ด๋‹น API๋ฅผ ํ˜ธ์ถœํ•˜๊ณ  ์‹ถ์„ ์ˆ˜๋„ ์žˆ๋‹ค. ๊ทธ๊ฒƒ์€ ์„œ๋ฒ„์—์„œ ์‹คํ–‰ ์ค‘์ธ getServerSideProps์™€ API Routes๋กœ ์ธํ•ด ์ถ”๊ฐ€์ ์ธ request๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค๊ธฐ ๋•Œ๋ฌธ์— ์ด๋Š” ๋ถˆํ•„์š”ํ•˜๊ณ  ๋น„ํšจ์œจ์ ์ธ ์ ‘๊ทผ์ด๋‹ค.

์ด์–ด์ง€๋Š” ์˜ˆ์ œ๋ฅผ ๋ณด๋ฉด, API route๋Š” CMS๋กœ๋ถ€ํ„ฐ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๋ฐ ์‚ฌ์šฉ๋œ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด API route๋Š” getServerSideProps๋กœ๋ถ€ํ„ฐ ์ง์ ‘ ํ˜ธ์ถœ๋œ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์ถ”๊ฐ€ ํ˜ธ์ถœ์ด ๋ฐœ์ƒํ•˜์—ฌ ์„ฑ๋Šฅ์ด ์ €ํ•˜๋œ๋‹ค. ๋Œ€์‹ ์— getServerSideProps ๋‚ด๋ถ€๋กœ API Route์—์„œ ์‚ฌ์šฉ๋˜๋Š” ๋กœ์ง์„ importํ•˜๋ฉด ๋œ๋‹ค. ์ด๊ฒƒ์€ CMS, ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋˜๋Š” ๋‹ค๋ฅธ API๋ฅผ getServerSideProps ์•ˆ์—์„œ ์ง์ ‘ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค.

getServerSideProps with Edge API Routes

getServerSideProps๋Š” Serverless ๋ฐ Edge Runtimes์—์„œ ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ์œผ๋ฉฐ ๋‘˜ ๋‹ค props๋ฅผ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜, ํ˜„์žฌ Edge Runtime์€ reponse ๊ฐ์ฒด์— ์ ‘๊ทผ ๊ถŒํ•œ์ด ์—†๋‹ค. ์ฆ‰ ์˜ˆ๋ฅผ ๋“ค์–ด getSErverSideProps์—์„œ ์ฟ ํ‚ค๋ฅผ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์—†๋‹ค๋Š” ์˜๋ฏธ์ด๋‹ค. response ๊ฐ์ฒด์— ์ ‘๊ทผ ๊ถŒํ•œ์„ ๊ฐ–๊ธฐ ์œ„ํ•ด์„œ๋Š” ๊ธฐ๋ณธ ๋Ÿฐํƒ€์ž„์ธ Node.js ๋Ÿฐํƒ€์ž„ ํ™˜๊ฒฝ์„ ๊ณ„์† ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.

์˜ˆ์ฒ˜๋Ÿผ, config ํŒŒ์ผ์„ ์ˆ˜์ •ํ•˜์—ฌ per-page basis๋ฅผ ์œ„ํ•œ runtime์„ ๋ช…์‹œ์ ์œผ๋กœ ์„ธํŒ…ํ•  ์ˆ˜ ์žˆ๋‹ค.

export const config = {
    runtime: 'nodejs',
}

Fetching data on the client side

์ž์ฃผ ์—…๋ฐ์ดํŠธ ๋˜๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ํฌํ•จํ•˜๋Š” ํŽ˜์ด์ง€๋ผ๋ฉด ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฌ์ „์— ๋ Œ๋”๋งํ•  ํ•„์š”์—†์ด client side์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๋‹ค. ์‚ฌ์šฉ์ž ์ƒ์„ธ ๋ฐ์ดํ„ฐ๋ฅผ ์˜ˆ๋กœ ๋“ค์–ด๋ณธ๋‹ค๋ฉด

  • ์ฒซ์งธ, ๋ฐ์ดํ„ฐ ์—†์ด ์ฆ‰์‹œ ํŽ˜์ด์ง€๋ฅผ ๋ณด์—ฌ์ค€๋‹ค. ํŽ˜์ด์ง€ ์ผ๋ถ€๋Š” Static Generation์„ ์‚ฌ์šฉํ•˜์—ฌ ์‚ฌ์ „์— ๋ Œ๋”๋ง๋  ์ˆ˜ ์žˆ๋‹ค. ๋ˆ„๋ฝ๋œ ๋ฐ์ดํ„ฐ์˜ ๋กœ๋”ฉ ์ƒํƒœ๋ฅผ ๋ณด์—ฌ์ค„ ์ˆ˜ ์žˆ๋‹ค.
  • ๊ทธ๋ฆฌ๊ณ  client side์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๊ณ  ์ค€๋น„๋˜์—ˆ์„ ๋•Œ ๋ณด์—ฌ์ค€๋‹ค.

์ด๊ฒƒ์€ ์˜ˆ๋ฅผ ๋“ค์–ด ์‚ฌ์šฉ์ž์˜ ๋Œ€์‹œ๋ณด๋“œ ํŽ˜์ด์ง€์— ์ ํ•ฉํ•˜๋‹ค. ์™œ๋ƒํ•˜๋ฉด ๋Œ€์‹œ๋ณด๋“œ๋Š” privateํ•˜๊ณ  ์‚ฌ์šฉ์ž์˜ ์ƒ์„ธ ํŽ˜์ด์ง€์ด๋ฉฐ SEO์™€ ๊ด€๋ จ์ด ์—†๊ธฐ ๋•Œ๋ฌธ์— ์‚ฌ์ „ ๋ Œ๋”๋ง์ด ํ•„์š”ํ•˜์ง€ ์•Š๋‹ค. ๋ฐ์ดํ„ฐ๋Š” ์ž์ฃผ ์—…๋ฐ์ดํŠธ๋˜๋ฏ€๋กœ ์š”์ฒญ ์‹œ ๊ฐ€์ ธ์™€์•ผ ํ•œ๋‹ค.

Using getServerSideProps to fetch data at request time

์•„๋ž˜ ์˜ˆ์ œ๋Š” request time์— ์–ด๋–ป๊ฒŒ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๊ณ  ๊ฒฐ๊ณผ๋ฅผ ์‚ฌ์ „์— ๋ Œ๋”๋ง ํ•˜๋Š”์ง€ ๋ณด์—ฌ์ค€๋‹ค.

function Page({ data }) {
    
}

export async function getServerSideProps() {
    const res = await fetch('https://.../data');
    const data = await res.json();
    
    return { props: { data } };
}

export default Page

Caching with Server-Side Rendering (SSR)

๋™์  ์‘๋‹ต์„ ์บ์‹ฑํ•˜๊ธฐ ์œ„ํ•ด getServerSideProps ์•ˆ์˜ caching headers(Cache-Control)์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, stale-while-revalidate๋ฅผ ์‚ฌ์šฉํ•ด๋ณด์ž.

export async function getServerSideProps({ req, res }) {
    res.setHeader(
        'Cache-Control',
        'public, s-maxage=10, stale-while-revalidate=59'
    )
    
    return {
        props: {},
    }
}

Does getServerSideProps render an error page

๋งŒ์•ฝ getServerSideProps ๋‚ด๋ถ€์— ์—๋Ÿฌ๊ฐ€ ์žˆ๋‹ค๋ฉด pages/500.js ํŒŒ์ผ์„ ๋ณด์—ฌ์ค„ ๊ฒƒ์ด๋‹ค. ์ด๊ฒƒ์„ ์–ด๋–ป๊ฒŒ ๋งŒ๋“œ๋Š”์ง€์— ๋Œ€ํ•ด ์ž์„ธํ•œ ๋‚ด์šฉ์€ 500 page ๋ฌธ์„œ๋ฅผ ํ™•์ธํ•ด๋ณด๋ฉด ๋œ๋‹ค. ๊ฐœ๋ฐœํ•˜๋Š” ๋™์•ˆ์—๋Š” ์ด ํŒŒ์ผ์ด ์‚ฌ์šฉ๋˜์ง€ ์•Š๊ณ  dev overlay ๊ฐ€ ๋Œ€์‹  ๋ณด์—ฌ์ง„๋‹ค.