๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๐Ÿ“š ์‹œ๋ฆฌ์ฆˆ/- ์ •์งํ•˜๊ฒŒ ๋ฐฐ์›Œ๋ณด๋Š” Next js

[์ •์งํ•˜๊ฒŒ ๋ฐฐ์›Œ๋ณด๋Š” Next.js] SSG๋กœ ๊ฒ€์ƒ‰ ์—”์ง„ ์ตœ์ ํ™” ๋…ธ๋ฆฌ๊ธฐ

by Wonit 2020. 12. 31.

ํ•ด๋‹น ๋ธ”๋กœ๊ทธ ์‹œ๋ฆฌ์ฆˆ๋Š” ์ •์งํ•˜๊ฒŒ ๋ฐฐ์›Œ๋ณด๋Š” Next js ์‹œ๋ฆฌ์ฆˆ๋กœ์จ ์ด 8๋ถ€์ž‘์œผ๋กœ ์ด๋ฃจ์–ด์ ธ ์žˆ์Šต๋‹ˆ๋‹ค.
Next.js๊ณต์‹ ํ™ˆํŽ˜์ด์ง€์—์„œ ์ด์•ผ๊ธฐํ•˜๋Š” ๋‚ด์šฉ์„ ์ตœ๋Œ€ํ•œ ์ดํ•ดํ•˜๊ธฐ ์‰ฝ๊ณ  ์ง๊ด€์ ์ด๊ฒŒ ๊ตฌ์„ฑํ•˜์˜€์Šต๋‹ˆ๋‹ค.

0. ๋ชฉ์ฐจ

1. create-next-app์œผ๋กœ next ๊ฐœ๋ฐœ ํ™˜๊ฒฝ ์„ธํŒ…ํ•˜๊ธฐ

2. create-next-app์—์„œ ๋งŒ๋‚œ ์ฒซ ๋ฒˆ์งธ ํ•ต์‹ฌ pages. ๊ทธ๋ฆฌ๊ณ  ๋™์  ๋ผ์šฐํŒ…

3. ํŽ˜์ด์ง€๋ฅผ ์—ฐ๊ฒฐํ•˜๊ธฐ ์œ„ํ•œ Link-Component ๊ทธ๋ฆฌ๊ณ  Pre-Fetch

Dynamic Routing๊ณผ Link๋ฅผ ์ด์šฉํ•ด ๊ฐ„๋‹จํ•œ ๊ฒŒ์‹œํŒ์„ ๋งŒ๋“ค์–ด๋ณด์ž.

4. Next.js์—์„œ head ํƒœ๊ทธ๋ฅผ ์กฐ์ž‘ํ•˜๋Š” ๋ฉ‹์ง„ ๋ฐฉ๋ฒ•

๋ฒˆ์™ธ & ์‹ค์Šต) ์ด๋ฏธ์ง€์™€ ๋™์˜์ƒ์„ ์ €์žฅํ•˜๊ณ  ์‚ฌ์šฉํ•ด๋ณด์ž.

5. ์›น์˜ ๋ฐœ์ „ ๊ณผ์ •์œผ๋กœ ๋ณด๋Š” SSG์™€ SSR

6. next์˜ ๋‘ ๋ฒˆ์งธ ํ•ต์‹ฌ Pre-Rendering

7. SSG๋กœ ๊ฒ€์ƒ‰ ์—”์ง„ ์ตœ์ ํ™” ๋…ธ๋ฆฌ๊ธฐ

8. ์ •์งํ•˜๊ฒŒ ๋ฐฐ์›Œ๋ณด๋Š” Next.js ์‹œ๋ฆฌ์ฆˆ๋ฅผ ๋งˆ์น˜๋ฉฐ..


์™œ ์šฐ๋ฆฌ๋Š” ํ”„๋กœ์ ํŠธ ๋””๋ ‰ํ† ๋ฆฌ์—์„œ index.htmlํŒŒ์ผ์„ ๋ณด์ง€ ๋ชปํ–ˆ์„๊นŒ?

 

๋งŒ์•ฝ ์šฐ๋ฆฌ๊ฐ€ ๊ธฐ๋ณธ์ ์œผ๋กœ ์ œ๊ณตํ•˜๋Š” Next์˜ SSG ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด? ์ฆ‰ pages ๋””๋ ‰ํ† ๋ฆฌ ์•„๋ž˜์— ๋ฆฌ์•กํŠธ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋งŒ๋“ค๊ฒŒ ๋œ๋‹ค๋ฉด HTML ํŒŒ์ผ์€ Build๋  ๋•Œ ์ƒ์„ฑ๋œ๋‹ค.

 

์ด ๋ง์ด ๋ฌด์Šจ ๋ง์ด๋ƒ๋ฉด ์šฐ๋ฆฌ๊ฐ€ ๊ฐœ๋ฐœ์„ ๋‹ค ํ–ˆ๊ณ  ๋นŒ๋“œ ์Šคํฌ๋ฆฝํŠธ๋งŒ ์ณ์•ผ ํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด๋ณด์ž.


๊ทธ๋Ÿผ ์•„๋งˆ ์ด๋Ÿฐ ๋ช…๋ น์–ด๋ฅผ ์น˜๊ฒŒ ๋  ๊ฒƒ์ด๋‹ค.

// next build ๋ช…๋ น์–ด๋ฅผ ์น  ๊ฒฝ์šฐ
$ next build

// npm script๋ฅผ ๋ฏธ๋ฆฌ ์ž‘์„ฑํ•ด ๋†“์€ ๊ฒฝ์šฐ
$ npm run build

// yarn script๋ฅผ ๋ฏธ๋ฆฌ ์ž‘์„ฑํ•ด ๋†“์€ ๊ฒฝ์šฐ
$ yarn build

๊ทธ๋Ÿผ ๊ทธ์ œ์„œ์•ผ HTML ํŒŒ์ผ์ด ์ƒ์„ฑ๋˜๊ณ  ๊ฐ๊ฐ ์š”์ฒญ์— ๋”ฐ๋ผ HTML์ด ์žฌ์‚ฌ์šฉ ๋œ๋‹ค.


์ด๊ฒƒ์ด ์šฐ๋ฆฌ๊ฐ€ ํ”„๋กœ์ ํŠธ ๋””๋ ‰ํ† ๋ฆฌ ๋‚ด์—์„œ htmlํŒŒ์ผ์„ ๋ณด์ง€ ๋ชปํ•œ ์ด์œ ์ด๋‹ค.

SSG

๊ธฐ๋ณธ์ ์œผ๋กœ ์šฐ๋ฆฌ๊ฐ€ ์ผ๋ฐ˜์ ์ธ ๋ฆฌ์•กํŠธ ์ปดํฌ๋„ŒํŠธ๋ฅผ Next์—์„œ ๊ฐœ๋ฐœํ–ˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด๋ณด์ž.


๊ทธ๋Ÿผ 2๊ฐ€์ง€ ์ƒํ™ฉ์„ ๋‚˜๋ˆŒ ์ˆ˜ ์žˆ๋Š”๋ฐ

  1. ์ปดํฌ๋„ŒํŠธ์—์„œ ์‚ฌ์šฉํ•  ์™ธ๋ถ€ ๋ฐ์ดํ„ฐ๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ
  2. ์ปดํฌ๋„ŒํŠธ์—์„œ ์‚ฌ์šฉํ•  ์™ธ๋ถ€ ๋ฐ์ดํ„ฐ๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ

๋กœ ๋‚˜๋ˆŒ ์ˆ˜ ์žˆ๋‹ค.

์ปดํฌ๋„ŒํŠธ์—์„œ ์‚ฌ์šฉํ•  ์™ธ๋ถ€ ๋ฐ์ดํ„ฐ๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ

์šฐ์„  ์™ธ๋ถ€ ๋ฐ์ดํ„ฐ ์‚ฌ์šฉ์ด ์—†๋Š” ๊ฒฝ์šฐ๋ฅผ ๋ณด์ž.

 

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

export default About

์—ฌ๊ธฐ์—๋Š” ๋ณด์ด๋‹ค์‹ถ์ด ์™ธ๋ถ€ ๋ฐ์ดํ„ฐ๊ฐ€ ์‚ฌ์šฉ๋˜์ง€ ์•Š์•˜๋‹ค.


์ฆ‰ next๊ฐ€ pre-render์„ ํ•˜๊ธฐ ์œ„ํ•ด์„œ ์‚ฌ์šฉ๋˜์–ด์•ผ ํ•  ์™ธ๋ถ€ ๋ฐ์ดํ„ฐ๊ฐ€ ์ œ๊ณต๋˜์ง€ ์•Š์•˜๋‹ค๋Š” ์†Œ๋ฆฌ์ธ๋ฐ, ์ด ๋•Œ๋Š” ๋‹จ์ˆœํžˆ HTML์„ build ํ•˜๊ฒŒ ๋˜๋Š” ๊ฒƒ์ด๋‹ค.

์ปดํฌ๋„ŒํŠธ์—์„œ ์‚ฌ์šฉํ•  ์™ธ๋ถ€ ๋ฐ์ดํ„ฐ๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ

์šฐ๋ฆฌ๊ฐ€ ์›น์„ ๋งŒ๋“ค๋‹ค ๋ณด๋ฉด ํŠน์ • ํŽ˜์ด์ง€์—์„œ๋Š” ์™ธ๋ถ€ ๋ฐ์ดํ„ฐ๊ฐ€ ํ•„์š”ํ•  ๋•Œ๊ฐ€ ์žˆ๋‹ค.

 

๊ทธ๊ฒŒ ๊ฐ™์€ ํŒŒ์ผ ์‹œ์Šคํ…œ์— ์กด์žฌํ•˜๋Š” dummy.json์ด๋˜ ์ผ๊ธฐ.mdwn์ด๋˜ ํ˜น์€ ๋‹ค๋ฅธ url์—์„œ api ํ˜ธ์ถœ์„ ํ•˜๋Š” ๊ฒƒ์ด๋˜ ๋ชจ๋“  ๊ฒฝ์šฐ์˜ ์™ธ๋ถ€ ๋ฐ์ดํ„ฐ๋ฅผ ์ผ์ปซ๋Š”๋‹ค.

 

๊ทธ ๋•Œ nextjs์—์„œ๋Š” ํŽ˜์ด์ง€ ์ปดํฌ๋„ŒํŠธ๋ฅผ exportํ•  ๋•Œ Next๊ฐ€ ์ œ๊ณตํ•˜๋Š” 2๊ฐ€์ง€ ํ•จ์ˆ˜๋ฅผ ์ƒํ™ฉ์— ๋งž๊ฒŒ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.

์ƒํ™ฉ์— ๋งž๊ฒŒ?

 

๊ทธ๋ ‡๋‹ค. ์ƒํ™ฉ์— ๋งž๊ฒŒ.

 

2๊ฐ€์ง€ ์ƒํ™ฉ์ด ์žˆ๋‹ค.

  1. ํŽ˜์ด์ง€์—์„œ ๋‚ด์šฉ์ด ์™ธ๋ถ€ ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ
  2. ํŽ˜์ด์ง€์˜ url์ด ์™ธ๋ถ€ ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ.

๊ฐ๊ฐ์˜ ๊ฒฝ์šฐ์— ๋”ฐ๋ผ ์‚ฌ์šฉํ•˜๋Š” ํ•จ์ˆ˜๊ฐ€ ๋‹ค๋ฅด๋‹ค.

 

์ฒซ ๋ฒˆ์งธ ์ƒํ™ฉ์ธ _ํŽ˜์ด์ง€์—์„œ ๋‚ด์šฉ์ด ์™ธ๋ถ€ ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ์—๋Š” getStaticProps ๋ผ๋Š” ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ดํ•˜๊ณ 

๋‘ ๋ฒˆ์งธ ์ƒํ™ฉ์ธ ํŽ˜์ด์ง€์—์„œurl์ด ์™ธ๋ถ€ ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ ์—๋Š” getStaticPaths ๋ผ๋Š” ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

 

getStaticProps ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ

ํŽ˜์ด์ง€ ๋‚ด๋ถ€์—์„œ ์™ธ๋ถ€ ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ์—๋Š” ๋น„๋™๊ธฐ ํ•จ์ˆ˜์ธ getStaticProps๋ฅผ export ํ•ด์ค˜์•ผ ํ•œ๋‹ค.


getStaticProps๋Š” async ํ•จ์ˆ˜์ด์–ด์•ผ ํ•˜๋Š”๋ฐ, ์ด ํ•จ์ˆ˜๋ฅผ Next.js ๋Š” ๋นŒ๋“œ ์‹œ์ ์— ํ•ด๋‹น ํ•จ์ˆ˜์—์„œ ๋ฐ˜ํ™˜๋œ props๋ฅผ ์ด์šฉํ•ด์„œ Pre-Rendering์„ ์ง„ํ–‰ํ•˜๊ฒŒ ๋œ๋‹ค.

// ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ
export async function getStaticProps(context) {
  return {
    props: {}
  }
}

// ES6 ํ™”์‚ดํ‘œ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ
export const getStaticProps = async(context) => {
  return {
    props: {}
  }
}

์—ฌ๊ธฐ์„œ props:{} ๋ผ๋Š” ๊ฐ์ฒด๊ฐ€ ์žˆ๋‹ค.


props ๊ฐ์ฒด๊ฐ€ ๋ฐ”๋กœ Pre-Rendering์„ ์œ„ํ•ด Next๊ฐ€ ํ•„์š”๋กœ ํ•˜๋Š” ๊ฐ’์ด๋‹ค.


ํ•ด๋‹น ๊ฐ’๋“ค์„ ์ด์šฉํ•ด์„œ ํ•ด๋‹น ์ปดํฌ๋„ŒํŠธ์— ๊ฐ’๋“ค์„ ์ถ”๊ฐ€ํ•ด์ค€๋‹ค.

 

์‚ฌ์šฉํ•ด๋ณด๊ธฐ

getStaticProps๋ฅผ ์‚ฌ์šฉํ•ด์„œ Pre-Rendering ํ•ด๋ณด๊ธฐ ์œ„ํ•ด์„œ ํ”„๋กœ์ ํŠธ ์•„๋ž˜ ๋””๋ ‰ํ† ๋ฆฌ์— data.js ํŒŒ์ผ์„ ์ƒ์„ฑํ•œ๋‹ค.

 

๊ทธ๋ฆฌ๊ณ  ํ•ด๋‹น data ํŒŒ์ผ์—์„œ import ํ•œ ๊ฐ’๋“ค์„ Pre-Rendering ํ•ด๋ณด์ž.

data.js

์›๋ž˜ data.js ํŒŒ์ผ์— ์žˆ๋Š” ๋ฐ์ดํ„ฐ๋“ค์ด api ์š”์ฒญ์—์˜ํ•ด์„œ ๊ฐ€์ ธ์™€์ง„ ๊ฐ’์ด์–ด์•ผ ํ•œ๋‹ค.


ํ•˜์ง€๋งŒ ์šฐ๋ฆฌ์˜ ๋ชฉ์ ์€ getStaticProps๋ฅผ ์•Œ์•„๊ฐ€๊ธฐ ์œ„ํ•œ ๊ฒƒ์ด๋ฏ€๋กœ data.jsํŒŒ์ผ ๊ฐ’๋“ค์ด ๋ฐ์ดํ„ฐ ์š”์ฒญ๋œ ๊ฐ’์ด๋ผ๊ณ  ๊ฐ€์ •ํ•˜์ž.

export const data = [
  { id: 1, name: "James", email: "james123@gmail.com" },
  { id: 2, name: "Andre", email: "Andre@naver.com" },
  { id: 3, name: "Michel", email: "Michel@hanmail.net" },
]

index.js

import React from "react";
import { data } from "../data/myInfo";
const Info = ({ jsonData }) => {
  return (
    <div>
      <h1>this is about</h1>
      {jsonData.map((data) => (
        <div key={data.id}>
          <h3>{data.name}</h3>
          <ul>
            <h4>{data.email}</h4>
          </ul>
        </div>
      ))}
    </div>
  );
};

export async function getStaticProps(context) {
  return {
    props: {
      jsonData: data,
    },
  };
}
export default Info;

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด import {data} from "../data/myInfo"๋กœ ๋ฐ›์€ ๋ฐ์ดํ„ฐ๋ฅผ Pre-Rendering ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜๋Š”๋ฐ, ๋งŒ์•ฝ ์—ฌ๊ธฐ์„œ data์˜ ๊ฐ’์ด ์—†๋‹ค๋ฉด notFount๋ฅผ ๋ฐ˜ํ™˜ํ•ด์ค„ ์ˆ˜ ์žˆ๋‹ค.

export async function getStaticProps(context) {

  if(!data) {
    return {
      notFound: true,
    }
  }

  return {
    props: {
      jsonData: data,
    },
  };
}
export default Info;

๊ทธ๋Ÿผ ๊ฒฐ๊ณผ๋กœ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํ™”๋ฉด์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

 

 

getStaticPaths ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ

ํŽ˜์ด์ง€์˜ url์—์„œ ์™ธ๋ถ€ ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ์—๋Š” ๋น„๋™๊ธฐ ํ•จ์ˆ˜์ธ getStaticPaths๋ฅผ export ํ•ด์ค˜์•ผ ํ•œ๋‹ค.

 

์ฃผ๋กœ ๋™์  ๋ผ์šฐํŒ… ์‹œ์— ๋งŽ์ด ์‚ฌ์šฉ๋˜๋Š” ๊ธฐ๋Šฅ์ด๋‹ค.

 

getStaticPathss๋Š” async ํ•จ์ˆ˜์ด์–ด์•ผ ํ•˜๋Š”๋ฐ, ์ด ํ•จ์ˆ˜๋ฅผ Next.js ๋Š” ๋นŒ๋“œ ์‹œ์ ์— ํ•ด๋‹น ํ•จ์ˆ˜์—์„œ ๋ฐ˜ํ™˜๋œ props๋ฅผ ์ด์šฉํ•ด์„œ
Pre-Rendering์„ ์ง„ํ–‰ํ•˜๊ฒŒ ๋œ๋‹ค.

// ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ
export async function getStaticPaths() {
  return {
    paths: [
      { params: { ... } }
    ],
    fallback: true or false
  };
}

// ES6 ํ™”์‚ดํ‘œ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ
export const getStaticPaths = async () => {
  return {
    paths: [
      {params: { ... }}
    ],
    fallBack: true or false
  }
}

์—ฌ๊ธฐ์„œ paths์™€ fallBack ๊ฐ’๋“ค์ด ์žˆ๋‹ค.

 

paths

getStaticPaths์˜ ํ•„์ˆ˜ ๊ฐ’์ด์ด๋ฉฐ, paths ์—์„œ ๋ฐ˜ํ™˜๋˜๋Š” params ๊ฐ’์œผ๋กœ ๋™์  ๋ผ์šฐํŒ… ๊ฒฝ๋กœ์˜ ์ด๋ฆ„์ด ๋œ๋‹ค.


์˜ˆ๋ฅผ ๋“ค์–ด

export const getStaticPaths = async () => {
  return {
    paths: [
      { params: { id: '1' } },
      { params: { id: '2' } },
    ]
  }
}

๊ณผ ๊ฐ™์ด ๋ฐ˜ํ™˜ ๋œ๋‹ค๋ฉด Next๋Š” static ํ•˜๊ฒŒ url์„ post/1๊ณผ post/2์„ ์ƒ์„ฑํ•ด๋‚ธ๋‹ค.

 

์ฃผ์˜ํ•ด์•ผํ•  ์ ์ด ์žˆ๋Š”๋ฐ, params๋Š” ํŽ˜์ด์ง€ ์ด๋ฆ„๊ณผ ๊ฐ™์•„์•ผ ํ•œ๋‹ค.

 

์˜ˆ๋ฅผ ๋“ค์–ด์„œ pages/posts/[postId]/[commentId] ๋ผ๋Š” ํŽ˜์ด์ง€ ์ด๋ฆ„์ด ์žˆ๋‹ค๋ฉด params ๊ฐ์ฒด๋Š” ๊ผญ postId์™€ commentId ๋ผ๋Š” ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•œ๋‹ค.

 

fallBack

fallBack ๊ฐ’๋„ ํ•„์ˆ˜ ๊ฐ’์ธ๋ฐ, fallBack ์€ Boolean ํƒ€์ž…์ด๋‹ค.

 

fallBack์ด false๋ผ๋ฉด getStaticPaths์—์„œ ๋ฐ˜ํ™˜๋˜์ง€ ์•Š๋Š” ๋ชจ๋“  ๊ฒฝ๋กœ๋Š” 404 ํŽ˜์ด์ง€๊ฐ€ ๋œ๋‹ค.

๋Œ“๊ธ€