Published on

nextjs 의 렌더링전략

Authors
  • avatar
    Name
    길재훈
    Twitter

nextjs 의 렌더링 전략

next.js 를 사용하고 있지만, 개념에 대한 정리를 하는것이 좋을 듯 싶다.
아직 알아야 할 것들이 많아 렌더링 전략에 대해서 자세히 알아본다.

nextjs 는 다른 react로 만들어진 framework 와는 다르게, static page 가 아닌 dynamic page를 제공한다.

어떤 페이지가 빌드 시점에 정적으로 생성되고, 실행 시점에 동적으로 제공될지 정할 수 있다.

이로 인해, serverside rendering 을 지원하며, 각 요청별로 페이지를 렌더링이 가능하다.

또한, 특정 컴포넌트를 클라이언트에서만 렌더링할 수 있다.

이 부분에 대해서 더 알아보자.

SSR(ServerSideRendering)

서버측에서 html 페이지를 만들어서 client 로 보내주는 방식을 server side rendering 이라고 불린다.

nextjs 에서도 이러한 기능을 제공하는데, 이러한 기능을 왜 제공하는지 알아야 한다.

SPA 의 한계

react 하면 빠질 수 없는 것이 바로 SPA 이다. SPA 는 단일페이지로 모든 페이지를 보여줄 수 있는 획기적인 방법이다.

SPAserver 에 의존한다기 보다는, client 측에서 작동된다.

SPA 는 비어있는 정적페이지에, Javascript 를 사용하여 페이지를 그려주는 방식을 사용한다.

그러므로, server 에서 모든 자원을 받을 필요 없어 비용을 절감할 수 있으며, client 측의 남는 자원을 사용하여 작동하므로, 더 빠르고 좋은 서비스를 제공할 수 있다

SPA 가 급발전하게 된것도 바로 이 부분이다. 하지만, 이러한 SPA도 반드시 Server 를 통해 렌더링된 페이지를 받아야만 하는 경우가 생긴다.

이는 데이터 검증 및 주요 API 등 Server 에서만 처리하는 것들과 함께, SEO 에도 영향을 끼치기 때문이다.

SEOWeb Bot 이 각 page 를 돌면서, 각 page 마다 점수를 매기는데, 점수를 높게 받을수록 상위에 노출된다.

이 점수를 매기는 기준이, SPA 가 아닌 SSR 에 초점이 맞추어져 있다는것이 문제이다.

보통 Bot 들은 Javascript 를 실행시키지 못한다. 단순히, HTML 만을 보고 정보를 수집한다.

앞써서, SPAjavascript 를 통해 page 를 그린다고 하였다 바로 이부분이 문제이다.

SPA 만 제공한다고 가정하면, Server 로 부터 HTML을 받지만, 비어있는 HTML 을 받을 것이고, 이후 Javascript 를 받은 이후에, HTML 의 화면을 그려준다.

즉, Bot비어있는 HTML을 이해하게된다는 것이다. 그러므로, SEO 는 당연 점수가 낮을수 밖에 없다.

SEO 를 위해 SSR 이 필요할 수 밖에 없는 상황이다.

NextJS 의 SSR 방식

next.js 는 이러한 부분을 해결하기 위해 SSR 을 지원한다. next.js 는 각 요청에 따라 HTML 을 동적으로 렌더링하고 client 로 전달한다.

이렇게 만들어진 HTMLjavascript 가 없는 page 이기에, 실상 어떠한 동작도 이루어지지 않는다.

단지, 정적인 page 만을 제공하여, CEO에 충족한 page 만을 제공한다. 이후, server 에서 rendering 한 페이지에 script 코드를 집어넣어서, Hydration 시켜준다.

Hydration 이란 정적인 페이지를 동적페이지로 만들어주기위해 Javascript 코드를 적용해주는것을 말한다.

이렇게 Hydration 과정을 거치면, Page 이동시 새로운 HTMLServer 로 부터 요청하지 않고, 동적페이지로 작동 가능하게 된다.

이러한 Hydration 기능을 통해 SSR 을 지원하는 SPA 로써 작동이 가능하게 된다.

이러한 부분으로 인해 next.js 는 기본적으로 build time 때 정적페이지를 만든다.

getServerSideProps

만약, 서버를 통해 받아온 데이터를 client 에 전달해서 사용해야 한다고 가정해보자.

이럴때, 유용하게 사용할 수 있는 next.js 의 내장함수가 getServerSideProps 이다.

export async function getServerSideProps() {
  const requestData = await fetch('https://server/api/list')
  const data = await requestData.json()

  return {
    props: {
      data
    }
  }
}

const Page(props: IData}) {
  return (
    <div>
      <ul>
        {
          props.data.lists.map((item) => (
            return (
              <li>
                {item}
              </li>
            )
          ))
        }
      </ul>
    </div>
  )
}

getServerSideProps 함수를 export 한다. nextjsbuild time 때, 이 함수를 export 하는 모든 page를 찾는다.

그리고, serverpage 를 요청할때 getServerSideProps 를 호출한다. 이때 중요한 것은 getServerSideProps 는 항상 server 에서 실행된다는 것이다.

이때 getServerSideProps 에서 반환하는 props 는 해당 page componentprops 인자로 전달한다.

이렇게 받은 props 인자는 page component 에서 사용가능하다. SSR 을 이런식으로 지원하며, Server 를 통해 받은 data를 동적으로 받아 HTMLredering 해 보내준다.

SSR 을 사용하여 page 처리할때(getServerSideProps안에서...), clinet 에서 사용하는 API는 사용 불가능하다. (ex: window, DOM)

CSR(ClientSideRendering)

CSR 은 필요한 기본 scriptcss, 기본 HTML 마크업만 전송하기에, 비어있는 page 를 제공한다. 이렇게 비어있는 page 안에는 root div 가 존재하는데, 이 root div에 해당 page 내용을 그려준다.

이로 인해, 새로고침없이 다른 페이지로 이동 가능하다.(page 내용을 그려준다.)

CSR 의 단점

CSR 은 전체 CSSJavascript 를 받아야 해서 server 로 부터 받는 시간이 오래걸릴 수 있으며, Javascript 를 통해 DOM 을 기르는데 시간이 걸리수 있다.

그래서, loding 하는 부분을 수초동안 보여주는등, page 로딩이 느려질 수 있다.

그리고 앞서서 이야기한 SEO 에도 좋은 점수를 받기 힘들다.

생각보다 귀찮은 CSR

CSRbrowser 상에서 작동한다. 이말은 SSR 이 끝난후, clientrendering 이 완료된 이후를 말한다.

이때, SSR 상에서 실수로 windowdocument 를 사용하여, error 가 발생하는 경우가 많은데, 이때는 useEffectdynamic import 및, typeof window === 'undefined' 를 사용하여 처리한다.

이중, dynamic 에 대해서는 조금더 알아본다.

dynamic

dynamic importmodule 을 동적으로 가져올때 사용하는 nextjs 의 기능이다.


import dynamic from 'next/dynamic'

const Page = () => {
  const Quill = dynamic(() => import ReactQuill from 'react-quill', { ssr: false })
  return (
    <div>
      <Quill />
    </div>
  )
}

이렇게, importmodule 을 가져오면서, 옵션으로 ssr: false 를 주면, 마치 useEffecttypeof window === 'undefined' 를 통해 client 인지 확인한것 처럼 동작하는것 처럼, 사용가능하다

즉, rendering 된 이후 CSR 에서 작동하도록 만들어준다. CSR 은 검색엔진에 노출 될 필요없는 페이지를 만드는 경우에 매우 좋다.

SSG(StaticSiteGeneration)

SSG 는 정적 사이트 생성이라고 부른다. SSGbuild timepage 를 미리 렌더링한다. 그러므로, 내용이 변하지 않는 페이지를 만들때 유용하게 사용가능하다.

이는 SSRCSR 에서 처럼, 내용의 변화가 없으며, 이를 통한 serverdata 를 요청할 필요가 없으므로 성능에 매우 좋다.

필요한 정보가 build timepage 로 전부 렌더링 되어 있기 때문에 그렇다.

이렇게 미리 렌더링되어 있다는것은, 정보 변경을 위해서는 매번 rebuild 가 필요하다는 것을 뜻한다.

이를 통해 조그마한 정보역시 리빌드를 해야하는 상황은 좋은 방법은 아니다. 이러한 불편함을 해결해주기위해 ISR(IncrementaStaticRegeneration) 을 제공한다.

ISR 은 만들어진 정적페이지에 어떤 내용을 업데이트할지, 재 랜더링할지 결정이 가능하다

getStaticProps

getStaticProps 함수는 build 시, pagerendering 할때 호출된다 이때, getServerSideProps 와는 달리, 한번 data 를 가져오면 다음 build 시에는 호출하지 않는다.

즉, getStaticProps 를 다시 호출하려면 다시 re-build 해야한다. 딱 봐도 불편해보인다.

이러한 부분을 처리하기 위해 revalidate 라는 option 을 제공한다.

revalidate 는 주기를 지정해서, 언제 re-build 할지 정할 수 있다. 값은 숫자를 사용하여 지정가능하다

revalidate 는 초단위로 숫자값을 지정한다. ex: 60 (1분)

이렇게, revalidate 를 사용해서 주기를 정하면 해당 주기마다 getStaticProps 가 실행되며, 헤당 data를 받아 props 로 넘겨주어 값 전달이 가능하다.

그래서

SSRSSG 를 통한 처리를 비교 알게 되었다.

SSR 은 동적페이지를 생성이 가능하며, SEOserver 측에서 처리해야할 정보를 처리할 수 있을때 사용한다.

SSGdata 에 대한 변경이 많이 없는 page 같은경우 사용하기에 좋다. 하지만 새로운 정보를 받기 위해서는 매번 re-build 를 해야 해서 불편한 부분이 있다.

이러한 단점을 없애기 위해 ISR 을 제공하여, re-build 주기를 정하여, 특정 주기마다 data 를 새로받아 처리할 수 있도록 한다.

즉, 빌드 시점에 페이지를 만들지, 페이지 요청시점에 만들지를 지정 가능하다고 생각할 수 있다.