[NextJS] Pre-rendering

๊ฐ•์€๋น„ยท2022๋…„ 7์›” 14์ผ
0

NextJS

๋ชฉ๋ก ๋ณด๊ธฐ
9/10
post-thumbnail

NextJS ๊ณต์‹๋ฌธ์„œ ๐Ÿ‘


Pre-rendering

  • ๊ธฐ๋ณธ์ ์œผ๋กœ NextJS๋Š” ๋ชจ๋“  ํŽ˜์ด์ง€๋ฅผ pre-rendering ํ•œ๋‹ค.
  • ํด๋ผ์ด์–ธํŠธ ์ธก ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๊ฐ€ ๋กœ๋“œ๋˜๊ธฐ ์ „์— ๋ฏธ๋ฆฌ ํŽ˜์ด์ง€ ๋ณ„ HTML ํŒŒ์ผ์„ ๋งŒ๋“ ๋‹ค.
  • ๋ฐ์ดํ„ฐ๊ฐ€ ์žˆ๋Š” HTML ํŒŒ์ผ์„ ๋ฏธ๋ฆฌ ๋งŒ๋“ค์–ด pre-renderingํ•˜๊ธฐ ๋•Œ๋ฌธ์—, ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์ด ์ข‹๊ณ  SEO์— ์ตœ์ ํ™”๋˜์–ด ์žˆ๋‹ค.

Pre-rendering vs No Pre-rendering


Static Generation ๐Ÿ†š Server-side Rendering

NextJS์—์„œ๋Š” ๋‘๊ฐ€์ง€ ํ˜•ํƒœ์˜ pre-rendering ๋ฐฉ์‹์„ ์ œ๊ณตํ•œ๋‹ค. ์–ธ์ œ HTML์„ ๋งŒ๋“œ๋ƒ์˜ ์ฐจ์ด๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค.

  1. Static Generation
    • ๋นŒ๋“œ ํƒ€์ž„์— HTML ํŒŒ์ผ์„ ์ƒ์„ฑํ•œ๋‹ค.
    • ๋ฏธ๋ฆฌ ๋งŒ๋“ค์–ด์ง„ HTML ํŒŒ์ผ์€ ์‚ฌ์šฉ์ž ์š”์ฒญ๋งˆ๋‹ค ์žฌ์‚ฌ์šฉ๋œ๋‹ค.
  2. Server-side Rendering
    • ์‚ฌ์šฉ์ž ์š”์ฒญ๋งˆ๋‹ค HTML ํŒŒ์ผ์„ ์ƒ์„ฑํ•œ๋‹ค.

SG vs SSR


๋‘˜ ์ค‘ ๋ฌด์—‡์„ ์‚ฌ์šฉํ•ด์•ผ ํ• ๊นŒ? ๐Ÿค”

  • ๊ณต์‹๋ฌธ์„œ์—์„œ๋Š” ์‚ฌ์šฉ์ž ์š”์ฒญ์— ์•ž์„œ ํŽ˜์ด์ง€๋ฅผ ๋ฏธ๋ฆฌ ๋ Œ๋”๋งํ•  ์ˆ˜ ์žˆ์œผ๋ฉด Static Generation์„ ์‚ฌ์šฉํ•˜๋ผ๊ณ  ๊ถŒ์žฅํ•œ๋‹ค.
    • ๋งˆ์ผ€ํŒ… ํŽ˜์ด์ง€, ๋ธ”๋กœ๊ทธ ํฌ์ŠคํŠธ ๋“ฑ
  • ๋งŒ์•ฝ ํŽ˜์ด์ง€๊ฐ€ ๋นˆ๋ฒˆํžˆ ์—…๋ฐ์ดํŠธ๋˜๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด์—ฌ์ค˜์•ผ ํ•˜๊ณ , ๋งค ์š”์ฒญ๋งˆ๋‹ค ํŽ˜์ด์ง€ ๋‚ด์šฉ์ด ๋ฐ”๋€Œ์–ด์•ผ ํ•œ๋‹ค๋ฉด Sever-side Rendering์„ ์ด์šฉํ•ด์•ผ ํ•œ๋‹ค.

Static Generation without data

๊ธฐ๋ณธ์ ์œผ๋กœ, ์™ธ๋ถ€ data๋ฅผ ๊ฐ€์ ธ์˜ฌ ํ•„์š” ์—†๋Š” ํŽ˜์ด์ง€๋Š” ์ž๋™์œผ๋กœ Static Generation์„ ํ†ตํ•ด pre-rendering ๋œ๋‹ค.

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

export default About;
// About page์˜ html ํŒŒ์ผ์ด ๋นŒ๋“œ ํƒ€์ž„์— ๋งŒ๋“ค์–ด์ง. (data fetching X)


Static Generation with data

์ผ๋ถ€ ํŽ˜์ด์ง€๋Š” pre-rendering์„ ์œ„ํ•ด ์™ธ๋ถ€ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์™€์•ผ ํ•  ์ˆ˜ ์žˆ๋‹ค. (ํŒŒ์ผ ์‹œ์Šคํ…œ ์ ‘๊ทผ, ์™ธ๋ถ€ API ํ˜ธ์ถœ ๋“ฑ๋“ฑ)
1. ํŽ˜์ด์ง€ ์ฝ˜ํ…์ธ ๊ฐ€ ์™ธ๋ถ€ ๋ฐ์ดํ„ฐ์— ์˜์กดํ•œ๋‹ค. => getStaticProps
2. ํŽ˜์ด์ง€ ๊ฒฝ๋กœ๊ฐ€ ์™ธ๋ถ€ ๋ฐ์ดํ„ฐ์— ์˜์กดํ•œ๋‹ค. => getStaticPaths


getStaticProps

// props๋ฅผ ์ „๋‹ฌ๋ฐ›์€ ๋ฐ์ดํ„ฐ๋ฅผ ์ด์šฉํ•˜์—ฌ ๋นŒ๋“œ ํƒ€์ž„ ๋•Œ html ํŒŒ์ผ ์ƒ์„ฑ
function Blog({ posts }) {
  return (
    <ul>
      {posts.map((post) => (
        <li>{post.title}</li>
      ))}
    </ul>
  )
}

export default Blog;

// ์ด ํ•จ์ˆ˜๋Š” ๋นŒ๋“œ ํƒ€์ž„๋•Œ ํ˜ธ์ถœ๋œ๋‹ค.
export async function getStaticProps() {
  const res = await fetch('https://.../posts');
  const posts = await res.json();
  return {
    props : { posts }, // ์™ธ๋ถ€์—์„œ ๊ฐ€์ ธ์˜จ ๋ฐ์ดํ„ฐ๋ฅผ props๋กœ ์ „๋‹ฌ
  };
}

๐Ÿ™Œ getStaticProps ๋” ์•Œ์•„๋ณด๊ธฐ


getStaticPaths

NextJS์—์„œ๋Š” Dynamic Routes๋ฅผ ์ด์šฉํ•˜์—ฌ ํŽ˜์ด์ง€๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.

  • pages/posts/[id].js
  • getStaticPath๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์›ํ•˜๋Š” ๊ฒฝ๋กœ์˜ ํŽ˜์ด์ง€๋“ค์„ ๋นŒ๋“œ ํƒ€์ž„ ๋•Œ pre-renderingํ•˜๋„๋ก ์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.
function Post({ post }){
  // Render post...
}

export default Post;

// ์ด ํ•จ์ˆ˜๋Š” ๋นŒ๋“œ ํƒ€์ž„ ๋•Œ ํ˜ธ์ถœ๋˜๊ณ , pre-renderํ•˜๊ณ  ์‹ถ์€ path๋“ค์„ ์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.
export async function getStaticPaths() {
  const res = await fetch('https://.../posts');
  const posts = await res.json();

  // pre-renderํ•˜๊ณ  ์‹ถ์€ path๋“ค
  const paths = posts.map((post) => ({
    params: { id: post.id },
  }));

  // paths ๋ฐฐ์—ด์— ์žˆ๋Š” ๊ฒฝ๋กœ์˜ ํŽ˜์ด์ง€๋งŒ ๋นŒ๋“œ ํƒ€์ž„ ๋•Œ pre-renderingํ•œ๋‹ค.
  // { fallback: false } : ๋‹ค๋ฅธ route๋“ค์€ 404
  return { paths, fallback: false };
}

// ๋นŒ๋“œ ํƒ€์ž„ ๋•Œ ํ˜ธ์ถœ
export async function getStaticprops({ params }){
  const res = await fetch(`https://.../posts/${params.id}`);
  const post = await res.json();
  
  return { props : { post } }; // ์™ธ๋ถ€์—์„œ ๊ฐ€์ ธ์˜จ ๋ฐ์ดํ„ฐ๋ฅผ props๋กœ ์ „๋‹ฌ
}

๐Ÿ™Œ getStaticPaths ๋” ์•Œ์•„๋ณด๊ธฐ


Server-side Rendering

Server-side Rendering์„ ์ด์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ getServerSideProps๋ฅผ exportํ•˜๊ฑฐ๋‚˜ getInitialProps๋ฅผ ์ด์šฉํ•ด์•ผ ํ•œ๋‹ค.

getSeverSideProps

function Page({ data }) {
  // Render data...
}

// ์ด ํ•จ์ˆ˜๋Š” ๋งค ์š”์ฒญ๋งˆ๋‹ค ํ˜ธ์ถœ๋œ๋‹ค.
export async function getServerSideProps() {
  const res = await fetch(`https://.../data`);
  const data = await res.json();

  return { props: { data } }; // ์™ธ๋ถ€์—์„œ ๊ฐ€์ ธ์˜จ ๋ฐ์ดํ„ฐ๋ฅผ props๋กœ ์ „๋‹ฌ
}

export default Page;
  • getServerSideProps๋Š” ๋งค ์š”์ฒญ๋งˆ๋‹ค ์„œ๋ฒ„์— ์˜ํ•ด ํ˜ธ์ถœ๋œ๋‹ค.
  • ๊ทธ๋ž˜์„œ ๋นˆ๋ฒˆํžˆ ์—…๋ฐ์ดํŠธ๋˜๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด์—ฌ์ฃผ๋Š” ํŽ˜์ด์ง€์—์„œ ์œ ์šฉํ•˜๊ฒŒ ์‚ฌ์šฉ๋œ๋‹ค.
  • getStaticProps์™€ ๋น„์Šทํ•˜๊ฒŒ ์ƒ๊ฒผ์ง€๋งŒ, ํ•จ์ˆ˜ ํ˜ธ์ถœ ์‹œ์ ์ด ๋‹ค๋ฅด๊ณ , ๋” ๋Š๋ฆฌ๋‹ค.

๐Ÿ™Œ getServerSideProps ๋” ์•Œ์•„๋ณด๊ธฐ


getInitialProps

getInitialProps๋„ SSR๋ฅผ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•œ๋‹ค.

function Page({ stars }) {
  return <div>Next stars: {stars}</div>
}

Page.getInitialProps = async (ctx) => {
  const res = await fetch('https://api.github.com/repos/vercel/next.js');
  const json = await res.json();
  return { stars: json.stargazers_count };
}

export default Page;
  • initial data population (์ดˆ๊ธฐ ๋ฐ์ดํ„ฐ ์ฑ„์šฐ๊ธฐ)์„ ํ†ตํ•ด ๋ฐ์ดํ„ฐ๊ฐ€ ์ฑ„์›Œ์ง„ HTML ํŒŒ์ผ์ด ๋งŒ๋“ค์–ด์ง€๊ณ  pre-rendering ํ•œ๋‹ค.

๐Ÿ™Œ getInitialProps ๋” ์•Œ์•„๋ณด๊ธฐ


getServerSideProps vs getInitialProps

  • ๋‘˜์˜ ๊ณตํ†ต์ ์€ ์„œ๋ฒ„ ์‚ฌ์ด๋“œ์—์„œ ์‹คํ–‰๋˜๊ณ  ๊ฐ€์ ธ์˜จ ๋ฐ์ดํ„ฐ๋กœ ์ฑ„์›Œ์ง„ html ํŒŒ์ผ์„ pre-rendering ํ•ด์ค€๋‹ค.
  • getServerSideProps๋Š” ํ•ญ์ƒ ์„œ๋ฒ„ ์‚ฌ์ด๋“œ์—์„œ ์‹คํ–‰๋˜์ง€๋งŒ, getInitialProps๋Š” ํด๋ผ์ด์–ธํŠธ ์‚ฌ์ด๋“œ์—์„œ๋„ ์‹คํ–‰๋  ์ˆ˜ ์žˆ๋‹ค.
    • ํŽ˜์ด์ง€๊ฐ€ ์ฒ˜์Œ ๋กœ๋“œ๋˜๋Š” ๊ฒฝ์šฐ, ์„œ๋ฒ„ ์‚ฌ์ด๋“œ์—์„œ ์‹คํ–‰๋˜๊ณ , next/link ํ˜น์€ next/router๋ฅผ ํ†ตํ•ด ํŽ˜์ด์ง€๋ฅผ ์ด๋™ํ•˜๋Š” ๊ฒฝ์šฐ ํด๋ผ์ด์–ธํŠธ ์‚ฌ์ด๋“œ์—์„œ ์‹คํ–‰๋œ๋‹ค.
  • getInitialProps๋Š” Automatic Static Optimization์„ ์ง€์›ํ•˜์ง€ ์•Š๋Š”๋‹ค. ๊ทธ๋ž˜์„œ์ธ์ง€ ๊ณต์‹๋ฌธ์„œ์—์„œ getServerSideProps๋ฅผ ์‚ฌ์šฉํ•˜๋ผ๊ณ  ๊ถŒ์žฅํ•œ๋‹ค.

Client-side Rendering

๋งŒ์•ฝ ํŽ˜์ด์ง€๊ฐ€ ๋ณด์—ฌ์ฃผ๋Š” ๋ฐ์ดํ„ฐ๊ฐ€ ์œ ์ € ์ •๋ณด์™€ ๊ฐ™์ด ๊ฐœ์ธ์ ์ด๊ฑฐ๋‚˜, SEO์™€ ๊ด€๋ จ ์—†๋‹ค๋ฉด ํ•ด๋‹น ํŽ˜์ด์ง€๋ฅผ pre-renderingํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค. ์ด๋Ÿด ๊ฒฝ์šฐ Client-side Rendering์„ ์ด์šฉํ•˜๋ฉด ๋œ๋‹ค.

getStaticProps๋‚˜ getServerSideProps ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•  ํ•„์š” ์—†์ด ํด๋ผ์ด์–ธํŠธ ์ธก์—์„œ api๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์™€ ๋ Œ๋”๋งํ•˜๋ฉด ๋œ๋‹ค.

function Profile() {
  const { data, status } = useQuery('/api/user', getUserInfo);

  if (status === "loading") return <div>loading...</div>;
  return <div>hello {data.name}!</div>;
}

๐Ÿ‘€ ํŽ˜์ด์ง€์˜ ์„ฑ๊ฒฉ์„ ํŒŒ์•…ํ•ด์„œ ๋ Œ๋”๋ง ๋ฐฉ์‹์„ ์ž˜ ์„ ํƒํ•ด์•ผ ๊ฒ ๋‹ค.

0๊ฐœ์˜ ๋Œ“๊ธ€