Front-end/Next.js

๐Ÿš€ Next.js์˜ Static Generation: ์ •์  ์ƒ์„ฑ์˜ ๋ชจ๋“  ๊ฒƒ ๐Ÿ–ผ๏ธ

xeunnie 2025. 2. 20. 01:00
728x90
๋ฐ˜์‘ํ˜•

๐Ÿš€ Next.js์˜ Static Generation: ์ •์  ์ƒ์„ฑ์˜ ๋ชจ๋“  ๊ฒƒ ๐Ÿ–ผ๏ธ

 

Next.js๋Š” React ์ƒํƒœ๊ณ„์—์„œ SSR(Server Side Rendering)๊ณผ SSG(Static Site Generation)๋ฅผ ๋งค๋„๋Ÿฝ๊ฒŒ ํ†ตํ•ฉํ•˜์—ฌ ๊ฐ•๋ ฅํ•œ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ตฌ์ถ•ํ•  ์ˆ˜ ์žˆ๋Š” ํ”„๋ ˆ์ž„์›Œํฌ์˜ ์ •์ ์ด์—์š”. ์˜ค๋Š˜์€ **์ •์  ์ƒ์„ฑ(Static Generation)**์— ๋Œ€ํ•ด ๊นŠ์ด ํŒŒ๊ณ ๋“ค์–ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์™œ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š”์ง€, ์–ด๋–ป๊ฒŒ ๊ตฌํ˜„ํ•˜๋Š”์ง€, ๊ทธ๋ฆฌ๊ณ  ์‹ค๋ฌด์—์„œ ์–ด๋–ค ์ด์ ์„ ์–ป์„ ์ˆ˜ ์žˆ๋Š”์ง€๊นŒ์ง€์š”. ๐Ÿ› ๏ธ

 

โœจ Static Generation์ด๋ž€?

 

์ •์  ์ƒ์„ฑ(Static Generation)์€ ๋นŒ๋“œ ํƒ€์ž„์— HTML ํŒŒ์ผ์„ ์ƒ์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ HTML์€ ์š”์ฒญ ์‹œ ์„œ๋ฒ„์—์„œ ์ƒ์„ฑ๋˜์ง€ ์•Š๊ณ , ๋ฏธ๋ฆฌ ๋นŒ๋“œ๋œ ์ƒํƒœ๋กœ ์‚ฌ์šฉ์ž์—๊ฒŒ ์ „๋‹ฌ๋ฉ๋‹ˆ๋‹ค.

์žฅ์ :

๋น ๋ฅธ ์†๋„: ์ •์  ํŒŒ์ผ์€ CDN(Content Delivery Network)์— ์บ์‹ฑ๋˜์–ด ์š”์ฒญ ์‹œ ์ฆ‰์‹œ ์ œ๊ณต๋ฉ๋‹ˆ๋‹ค.

๋ณด์•ˆ: ์„œ๋ฒ„ ๋กœ์ง์ด ์‹คํ–‰๋˜์ง€ ์•Š์œผ๋ฏ€๋กœ ๊ณต๊ฒฉ ํ‘œ๋ฉด์ด ์ ์Šต๋‹ˆ๋‹ค.

SEO ์ตœ์ ํ™”: ๊ฒ€์ƒ‰ ์—”์ง„์€ ์ •์  HTML ํŒŒ์ผ์„ ๋ฐ”๋กœ ํฌ๋กค๋งํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

๐Ÿ’ก Static Generation์ด ์ ํ•ฉํ•œ ๊ฒฝ์šฐ

 

๐Ÿ“ ์ •์  ์ฝ˜ํ…์ธ 

 

๋ธ”๋กœ๊ทธ, ๋ฌธ์„œ, ๋งˆ์ผ€ํŒ… ํŽ˜์ด์ง€ ๋“ฑ ๋ณ€๊ฒฝ ๋นˆ๋„๊ฐ€ ๋‚ฎ์€ ์ฝ˜ํ…์ธ ์— ์ ํ•ฉํ•ฉ๋‹ˆ๋‹ค.

 

๐Ÿ“ฆ API ๊ธฐ๋ฐ˜ ์ฝ˜ํ…์ธ 

 

API์—์„œ ๊ฐ€์ ธ์˜จ ๋ฐ์ดํ„ฐ๊ฐ€ ๋นˆ๋ฒˆํžˆ ์—…๋ฐ์ดํŠธ๋˜์ง€ ์•Š๋Š”๋‹ค๋ฉด, ์ด๋ฅผ ์ •์ ์œผ๋กœ ๋นŒ๋“œํ•˜์—ฌ ํšจ์œจ์„ฑ์„ ๊ทน๋Œ€ํ™”ํ•  ์ˆ˜ ์žˆ์–ด์š”.

 

๐Ÿ”ง Static Generation ๊ตฌํ˜„ ๋ฐฉ๋ฒ•

 

Next.js์—์„œ๋Š” getStaticProps์™€ getStaticPaths ๋‘ ๊ฐ€์ง€ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ •์  ์ƒ์„ฑ์„ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค.

 

1๏ธโƒฃ getStaticProps: ์ •์  ๋ฐ์ดํ„ฐ๋ฅผ ๋นŒ๋“œ ํƒ€์ž„์— ๊ฐ€์ ธ์˜ค๊ธฐ

 

๊ธฐ๋ณธ ์‚ฌ์šฉ๋ฒ•

 

export async function getStaticProps() {

  const res = await fetch('https://api.example.com/posts');

  const posts = await res.json();

 

  return {

    props: {

      posts

    }

  };

}

 

**getStaticProps**๋Š” ๋นŒ๋“œ ํƒ€์ž„์— ์‹คํ–‰๋˜์–ด ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.

๋ฐ˜ํ™˜๋œ props๋Š” ํŽ˜์ด์ง€ ์ปดํฌ๋„ŒํŠธ์— ์ „๋‹ฌ๋ฉ๋‹ˆ๋‹ค.

 

์˜ˆ์ œ: ๋ธ”๋กœ๊ทธ ํฌ์ŠคํŠธ ๋ฆฌ์ŠคํŠธ

 

const Blog = ({ posts }) => (

  <div>

    <h1>Blog</h1>

    <ul>

      {posts.map(post => (

        <li key={post.id}>{post.title}</li>

      ))}

    </ul>

  </div>

);

 

export default Blog;

 

export async function getStaticProps() {

  const res = await fetch('https://api.example.com/posts');

  const posts = await res.json();

 

  return {

    props: {

      posts

    }

  };

}

 

2๏ธโƒฃ getStaticPaths: ๋™์  ๋ผ์šฐํŒ…๊ณผ ์ •์  ์ƒ์„ฑ

 

๋™์ž‘ ์›๋ฆฌ

 

getStaticPaths๋Š” ๋™์  ๊ฒฝ๋กœ([id])๋ฅผ ์ •์ ์œผ๋กœ ๋นŒ๋“œํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

 

๊ธฐ๋ณธ ์‚ฌ์šฉ๋ฒ•

 

export async function getStaticPaths() {

  const res = await fetch('https://api.example.com/posts');

  const posts = await res.json();

 

  const paths = posts.map(post => ({

    params: { id: post.id.toString() }

  }));

 

  return {

    paths,

    fallback: false

  };

}

 

paths: ์ •์ ์œผ๋กœ ์ƒ์„ฑํ•  ๊ฒฝ๋กœ๋ฅผ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค.

fallback:

false: ์ง€์ •๋œ ๊ฒฝ๋กœ ์™ธ์—๋Š” 404๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

true: ์š”์ฒญ ์‹œ ๊ฒฝ๋กœ๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

'blocking': ์š”์ฒญ์ด ๋๋‚  ๋•Œ๊นŒ์ง€ ์‚ฌ์šฉ์ž์—๊ฒŒ ์•„๋ฌด๊ฒƒ๋„ ํ‘œ์‹œํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

 

์˜ˆ์ œ: ๋ธ”๋กœ๊ทธ ์ƒ์„ธ ํŽ˜์ด์ง€

 

const Post = ({ post }) => (

  <div>

    <h1>{post.title}</h1>

    <p>{post.body}</p>

  </div>

);

 

export default Post;

 

export async function getStaticProps({ params }) {

  const res = await fetch(`https://api.example.com/posts/${params.id}`);

  const post = await res.json();

 

  return {

    props: {

      post

    }

  };

}

 

export async function getStaticPaths() {

  const res = await fetch('https://api.example.com/posts');

  const posts = await res.json();

 

  const paths = posts.map(post => ({

    params: { id: post.id.toString() }

  }));

 

  return {

    paths,

    fallback: false

  };

}

 

๐Ÿ“Š ISR(Incremental Static Regeneration)์™€์˜ ์ฐจ์ด์ 

 

Next.js๋Š” SSG์— ISR์„ ์ถ”๊ฐ€ํ•˜์—ฌ, ๊ธฐ์กด ๋นŒ๋“œ ํƒ€์ž„์—๋งŒ ์ƒ์„ฑ๋˜๋˜ ์ •์  ํŒŒ์ผ์„ ๋™์ ์œผ๋กœ ์—…๋ฐ์ดํŠธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

ISR ์‚ฌ์šฉ ์˜ˆ์ œ

 

export async function getStaticProps() {

  const res = await fetch('https://api.example.com/posts');

  const posts = await res.json();

 

  return {

    props: {

      posts

    },

    revalidate: 10 // 10์ดˆ๋งˆ๋‹ค ์žฌ์ƒ์„ฑ

  };

}

 

revalidate: ํŽ˜์ด์ง€๊ฐ€ **์ง€์ •๋œ ์‹œ๊ฐ„(์ดˆ)**๋งˆ๋‹ค ๋‹ค์‹œ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.

 

๐Ÿ”‘ Static Generation์˜ ์ฃผ์š” ์ด์ 

1. SEO ์ตœ์ ํ™”

์ •์  HTML ํŒŒ์ผ์€ ๊ฒ€์ƒ‰ ์—”์ง„์ด ์‰ฝ๊ฒŒ ํฌ๋กค๋งํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

2. ๋น ๋ฅธ ๋กœ๋“œ ์†๋„

CDN์—์„œ ์บ์‹ฑ๋œ ์ •์  ํŒŒ์ผ์„ ์ง์ ‘ ์ œ๊ณตํ•˜๋ฏ€๋กœ ์ง€์—ฐ ์‹œ๊ฐ„์ด ๊ฑฐ์˜ ์—†์Šต๋‹ˆ๋‹ค.

3. ๋น„์šฉ ํšจ์œจ์„ฑ

์„œ๋ฒ„ ์š”์ฒญ์ด ์ค„์–ด๋“ค์–ด ๋น„์šฉ์„ ์ ˆ๊ฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

4. ๋ณด์•ˆ ๊ฐ•ํ™”

์„œ๋ฒ„์‚ฌ์ด๋“œ ๋กœ์ง์ด ์—†์œผ๋ฏ€๋กœ ๊ณต๊ฒฉ ํ‘œ๋ฉด์ด ์ค„์–ด๋“ญ๋‹ˆ๋‹ค.

 

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

 

์ ํ•ฉํ•œ ๊ฒฝ์šฐ:

๋ธ”๋กœ๊ทธ, ๋ฌธ์„œ ์‚ฌ์ดํŠธ

๋ณ€๊ฒฝ์ด ์ ์€ ๋งˆ์ผ€ํŒ… ํŽ˜์ด์ง€

SEO๊ฐ€ ์ค‘์š”ํ•œ ์ฝ˜ํ…์ธ 

 

๋ถ€์ ํ•ฉํ•œ ๊ฒฝ์šฐ:

์‚ฌ์šฉ์ž ๋งž์ถคํ˜• ๋ฐ์ดํ„ฐ(๋กœ๊ทธ์ธ ์ƒํƒœ, ๊ถŒํ•œ ๋“ฑ)

์ž์ฃผ ๋ณ€๊ฒฝ๋˜๋Š” ์ฝ˜ํ…์ธ (์˜ˆ: ์ฃผ์‹ ๊ฐ€๊ฒฉ)

 

๐Ÿ“Œ ์‹ค๋ฌด์—์„œ์˜ ํŒ

1. API ํ˜ธ์ถœ ์ฃผ์˜:

SSG๋Š” ๋นŒ๋“œ ํƒ€์ž„์— ์‹คํ–‰๋˜๋ฏ€๋กœ, ๋ฐ์ดํ„ฐ ์†Œ์Šค๊ฐ€ ์•ˆ์ •์ ์ด๊ณ  ๋น ๋ฅธ ์‘๋‹ต์„ ์ œ๊ณตํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

2. ISR๊ณผ ์กฐํ•ฉ:

์ž์ฃผ ์—…๋ฐ์ดํŠธ๋˜๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋ ค๋ฉด ISR๊ณผ SSG๋ฅผ ์กฐํ•ฉํ•˜์„ธ์š”.

3. Fallback ์„ค์ •:

๋™์  ๋ผ์šฐํŒ…์˜ ๊ฒฝ์šฐ fallback ์˜ต์…˜์„ ์ƒํ™ฉ์— ๋งž๊ฒŒ ์„ค์ •ํ•˜์„ธ์š”. ์‹ค์‹œ๊ฐ„ ๋ฐ์ดํ„ฐ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋ ค๋ฉด 'blocking'์ด ์ ํ•ฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

๐ŸŒท์ „์„ค์˜ ๊ฐœ๋ฐœ์ž๊ฐ€ ๋˜์–ด๋ด…์‹œ๋‹น!๐ŸŒท

 

Static Generation์€ ๋น ๋ฅธ ๋กœ๋”ฉ ์†๋„์™€ SEO ์ตœ์ ํ™”๋ฅผ ๋ชจ๋‘ ์žก์„ ์ˆ˜ ์žˆ๋Š” ๊ฐ•๋ ฅํ•œ ๊ธฐ๋Šฅ์ž…๋‹ˆ๋‹ค. Next.js์˜ ์ •์  ์ƒ์„ฑ์„ ํ™œ์šฉํ•˜์—ฌ ์ตœ๊ณ ์˜ ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์„ ์ œ๊ณตํ•ด ๋ณด์„ธ์š”! ๐Ÿš€

728x90
๋ฐ˜์‘ํ˜•