NextJS Pre-rendering(SSG & SSR)

iskkiri2022년 08월 05일
Next.js
SSR
Server Side Rendering
Static Side Generation
SSG
getServerSideProps
getStaticProps
getStaticPaths
NextJS Pre-rendering(SSG & SSR)

리액트는 별도의 처리를 하지 않으면 기본적으로 Client Side Rendering(CSR)로 페이지를 렌더링합니다.

반면에 리액트 프레임 워크인 NextJS는 default로 페이지를 Pre-rendering합니다. Pre-rendering이란 HTML파일을 미리 생성하는 것을 말합니다.

Pre-rendering을 하게 되면 성능 상의 이점이나 Search Engine Optimization(SEO, 검색 엔진 최적화)에 유리합니다.

 

NextJS에서 Pre-rendering에는 Server Side Rendering(SSR)과 Static Site Generation(SSG) 2가지가 있습니다.

 

  • Server Side Rendering(SSR)은 매 요청마다 HTML을 생성합니다.
  • Static Site Generation(SSG)는 빌드 시 HTML을 생성하고, 각 요청에 대해서 미리 생성한 HTML을 재사용합니다.

 

위 내용대로면 성능 상 SSG가 더 효율적이라는 것을 알 수 있습니다. 그래서 NextJS 문서에서도 SSG를 권장하고 있습니다.

그러나 페이지의 내용이 빈번하게 업데이트 되는 경우라면 SSR을 선택할 수도 있습니다.

 

이 블로그도 이전에는 SSR을 적용했다가 현재는 SSG방식과 Incremental Static Regeneration(ISR)방식을 사용하고 있습니다.

ISR 대해서는 다음 포스팅에서 소개하도록 하겠습니다.

 

Server Side Rendering(SSR, getServerSideProps)

 

먼저 NextJS SSR 대해서 살펴보겠습니다. NextJS에서 SSR 적용하기 위해서는 다음과 같이 'getServerSideProps'라는 이름의 비동기 함수를 page 컴포넌트 안에서 정의합니다. 그리고 정의한 함수를 export 해줘야 합니다.

 

// src/pages/posts/[id].tsx

export const getServerSideProps: GetServerSideProps = async ({ params }) => {
  const { id } = params;

  const post = await axios.get<Post>(`/api/post/${id}`);


  if (!post) {
    return { notFound: true };
  }


  return {
    props: { post },
  };
};

 

/src/pages/posts/[id].tsx 와 같이 dynamic routes를 사용하는 경우에는 path가 함수의 인자로 들어옵니다.

예를 들어, https://devkkiri.com/posts/777 로 페이지를 방문하면 getServerSideProps의 인자로 path가 들어오며, parms.id = 777 이 됩니다.

그리고 함수의 반환 값은 페이지 컴포넌트의 props 전달되어 서버 사이드에서 전달받은 데이터를 가지고 HTML 생성합니다.

 

Static Site Generation (SSG, getStaticProps & GetStaticPaths)

 

NextJS에서 SSG 적용하기 위해서는 'getStaticProps' 라는 이름의 비동기 함수를 page 컴포넌트 안에서 정의합니다. 그리고 정의한 함수를 export 합니다.

 

export const getStaticProps: GetStaticProps = async () => {
  return {
    props: { message: 'Next.js is awesome' }, // page 컴포넌트의 props으로 전달됩니다.
  };
};

 

위에서 설명했듯이 SSG는 빌드 시 HTML파일을 생성합니다. 따라서 Dynamic Routes에서는 빌드 시 routes들의 값을 알 수 없기 때문에 문제가 발생합니다.

그래서 Dynamic Routes에서 SSG 적용하기 위해서는 'getStaticPaths' 사용해야 합니다.

 

export const getStaticPaths: GetStaticPaths = async () => {
  const { data: posts } = await axios.get<PostWithOnlyId[]>('/api/posts/list');

  const paths = posts.map((post) => {
    return { params: { id: post.uid } };
  });

  return { paths, fallback: false };
};

 

빌드 시 getStaticPaths에서 반환한 paths는 getStaticProps로 전달됩니다. fallback은 false, true, "blocking" 중 하나의 값을 가집니다.

 

  • fallback: false

    => 빌드 시 생성된 path 외에는 Not Found 페이지를 반환합니다.

  • fallback: true 
    => 빌드시 생성된 path 외의 페이지로 요청이 들어오면, 첫 요청에서 새로운 HTML을 생성합니다. 생성된 페이지는 pre-render list에 추가됩니다. HTML을 생성하는 동안 fallback 버전의 페이지를 보여줍니다.
  • fallback: "blocking" 
    =>빌드시 생성된 path 외의 페이지로 요청이 들어오면, 요청에서 새로운 HTML 생성합니다. 생성된 페이지는 pre-render list 추가됩니다. 요청에서 SSR 진행하기 때문에, HTML 생성하는 동안 특정 페이지를 보여줄 수는 없습니다.

 

export const getStaticProps: GetStaticProps = async ({ params }) => {
  const { id } = params;

  const post = await axios.get<Post>(`/api/post/${id}`);

  return {
    props: { post },
  };
};

 

현재 이 블로그에는 fallback을 true로 설정해놨습니다.

만약 fallback을 false로 설정하게 되면 새로 작성한 글에 대해서는 Not Found(404 page)가 나타나기 때문입니다. 그렇다고 글을 작성할 때마다 npm run build를 입력하여 매번 빌드를 하는 것은 굉장히 비효율적이겠죠?

 

페이지가 굉장히 빈번하게 업데이트 되어 내용이 변경되는 경우가 아니라면 getServerSideProps(SSR)을 적용하는 것보다는 getStaticProps(SSG)를 적용하는 것이 좋습니다. 그렇다면 내용이 자주 바뀌는 것은 아니더라도 가끔 변경되는 경우에는 어떨까요?

예를 들어, 블로그에서 글을 작성했는데 글에 오타가 있거나 잘못된 내용이 있어서 수정해야 하는 경우를 생각해보죠

getStaticProps는 미리 페이지를 생성해두기 때문에 내용을 수정하여도, 수정한 내용이 반영되지 않습니다.

물론 내용을 변경하고, 새롭게 npm run build로 페이지를 모두 다시 빌드하면 수정한 내용이 반영됩니다. 그러나 굉장히 비효율적인 방식이죠. 페이지가 수백개, 수천개, 그 이상이라고 하면 말도 안되는 방식입니다.

 

이런 경우에 Incremental Static Regeneration(ISR)을 적용해야 합니다. 이는 다음 포스팅에서 소개하도록 하겠습니다.

 

참고로 getServerSideProps getStaticProps 모두 주의해야할 점이 있습니다. 모두 서버 사이드에서 page 컴포넌트로 props 데이터를 넘기는데, 데이터는 html 에서 모두 확인이 가능합니다.

 

 

이 블로그의 특정 게시물에 들어가서 개발자 도구를 연 화면입니다.

만일 회원의 개인정보와 같은 민감한 정보를 props 넘기게 되면 client side에서 모두 확인이 가능하기 때문에 props 민감한 데이터를 넘겨서는 안됩니다.

 

잘못된 내용이나 궁금한 내용이 있으면 댓글을 남겨주세요.

NextJS Pre-rendering(SSG & SSR)