[NextJS] Static Site Generation

상현·2023년 12월 19일
0

NextJS

목록 보기
3/6
post-thumbnail

NextJS의 큰 특징중 하나는 사전에 렌더링한 후 클라이언트에게 보여준다는 점이 있었다. NextJS에는 두 가지 사전 렌더링 방법이 있다. 하나는 Static Site Generation(SSG), 또 하나는 Server Side Rendering(SSR)이다. 둘 중 권장되는 방식은 SSG이다.

SSG의 개념은 간단하다. 빌드를 할 때 미리 페이지를 생성하는 것이다. 즉, 모든 HTML 코드와 그 외의 모든 필요한 데이터를 사전에 준비한다. 빌드시에 이미 페이지가 구성되어 배포시에는 CDN을 통해 제공된다.

클라이언트에게 페이지가 표시된 이후에는 상호작용을 거쳐 일반적인 React 앱이 된다.

📚 정적인 데이터만 있는 경우 자동으로 사전 렌더링을 한다.

외부 데이터가 필요한 경우

사전 렌더링을 해야하는데, 페이지에 비동기 함수를 호출하여 데이터를 불러와야 하는 경우가 있다. 이 경우 pages 폴더 아래에 있는 컴포넌트에서, getStaticProps라는 이름의 비동기 함수를 호출하면 된다.

getStaticProps는 해당 컴포넌트로 전달되는 propsreturn 하며 특이한 점은 이 함수 내에서는 서버사이드에서만 사용할 수 있는 변수나 메서드도 호출할 수 있다는 것이다. 그리고 이 함수내에 작성된 코드는 클라이언트로 전달되지 않는다.

import ProductType from "../type/ProductType";
import path from "path";
import fs from "fs";

// getStaticProps 함수에서 반환한 props를 받아온다.
const Home = (props: { products: ProductType[] }) => {
  const { products } = props;
  return (
    <div>
      <ul>
        {products.map((product) => {
          return <li key={product.id}>{product.title}</li>;
        })}
      </ul>
    </div>
  );
};

export default Home;

// 렌더링 전에 실행 된다.
export async function getStaticProps() {
  // path, process 등 서버사이드(node.js)에서만 사용 가능한 메서드 호출 가능
  const filePath = path.join(process.cwd(), "data", "dummy-backend.json");
  const data: { products: ProductType[] } = JSON.parse(
    fs.readFileSync(filePath).toString()
  );

  // 데이터를 Home 컴포넌트의 props로 넘긴다
  return {
    props: {
      products: data.products,
    },
  };
}

getStaticProps 를 통한 사전 렌더링은 npm build 단계에서 페이지를 미리 생성한다.

Incremental Static Regeneration (ISR)

만약 외부에서 불러오는 데이터를 이용하여 페이지를 사전 생성했는데, 시간이 지나 외부 데이터가 오래된 데이터라면 어떻게 해야할까? NextJS에서는 이에 대한 해결방안도 제시한다.

getStaticProps 함수의 리턴값에 revalidate 값을 지정하면 지정한 숫자(초)가 지나면 다시 build 하여 배포된다.
만약 revalidate 의 값으로 10을 지정했다면, 스스로 10초마다 렌더링하여 재배포 하는것은 아니다. 어떤 사용자에 의해 페이지 요청이 있고, 마지막 배포에서 10초가 지났을 경우에 다시 빌드하여 배포한다.

export async function getStaticProps() {
  const filePath = path.join(process.cwd(), "data", "dummy-backend.json");
  const data: { products: ProductType[] } = JSON.parse(
    fs.readFileSync(filePath).toString()
  );

  return {
    props: {
      products: data.products,
    },
    revalidate: 10,
  };
}

npm build시 ISR이 추가되어 표시된것을 확인할 수 있다.

추가 구성 옵션

getStaticProps의 리턴값으로 다음과 같은 값을 사용할 수 있다.

notFound

export async function getStaticProps() {
  const filePath = path.join(process.cwd(), "data", "dummy-backend.json");
  const data: { products: ProductType[] } = JSON.parse(
    fs.readFileSync(filePath).toString()
  );

  if (data.products.length === 0) {
    return { notFound: true };
  }

}

notFound 속성에 true를 주고 리턴하면 404페이지로 이동한다.

redirect

redirect 속성안에 destination 속성값을 추가하여 리턴하면 해당 문자열의 페이지로 이동한다.

if (!data) {
    return {
      redirect: {
        destination: "/no-data",
      },
    };
  }

getStaticPaths

getStaticProps 라는 함수를 통해 페이지를 사전에 렌더링하여 보여줄 수 있었다. Next.js 에는 파일명의 대괄호([])를 사용하여 동적 페이지를 구성하는 방법이 있었다. 이런 경우에는 어떻게 페이지를 사전 렌더링할까?

만약 동적 페이지에서 getStaticProps 를 사용하면 다음과 같은 에러가 나타난다.

에러 메시지에 출력된 해결 방안에도 써있듯이 getStaticPaths라는 함수를 통하여 가능하게할 수 있다.

다음과 같이 paths에 미리 사전 렌더링할 경로들을 지정해주고, params에 동적 경로에 들어가는 id를 적어주면 된다. 또한 fallback 값을 반드시 지정해줘야 한다.

아래 예시 코드는 파일 이름이 [pid].tsx 인 경우이다.

export const getStaticPaths: GetStaticPaths = async () => {
  return {
    paths: [
      { params: { pid: "p1" } },
      { params: { pid: "p2" } },
      { params: { pid: "p3" } },
    ],
    fallback: false,
  };
};

fallback

  1. fallback: false
    • paths 에서 지정된 경로외에는 전부 404 페이지를 보여준다.
  2. fallback: true
    • paths 경로외의 페이지 접근시 fallback 페이지를 우선 보여준다.
    • 페이지를 렌더링한 후, 렌더링이 완료 되면 사용자에게 보여준다.
    • 그 이후 사용자들에게는 미리 렌더링한 페이지를 보여준다.
  3. fallback: "blocking"
    • paths 경로외의 페이지 접근시 페이지가 렌더링 될때까지 기다린다.
    • 페이지가 렌더링되면 사용자에게 보여준다.
    • 그 이후 사용자들에게는 미리 렌더링한 페이지를 보여준다.

getStaticPaths는 언제 실행 될까?

getStaticPaths는 해당 페이지에 요청이 들어와 빌드를 해야하는 경우에만 실행된다.

📚 dev 환경에서는 매 요청마다 재실행된다.

profile
프론트엔드 개발자

0개의 댓글