nextJS

[nextJS] nextJS(page router)의 빌드 방식에 대해 알아보자.(pre-render, static, SSR, SSG)

tea-tea 2024. 2. 20. 20:12

nextJS는 react를 기반으로 하는 풀스택 프레임워크다. nextJS는 react로 프로젝트를 만들 때 많이 사용하는 CRA(creat-react-app)과 어떤 차이가 있을까. 이 글은 여러 차이점 중에서도 빌드 방식에 대해 다루려고 한다.

 

1. react의 JSX 컴포넌트

react의 컴포넌트는 html이 아니라 javascript로 만들어진 결과물이다. 이런 컴포넌트는 서버단에서 생성되지 않고 클라이언트단에서 생성된다. (그래서 페이지 소스를 보면, html 요소가 존재하지 않는다.) 업계에서는 이런 방식을 CSR(Client-Side-Rendering)이라고 부른다. CSR은 아래와 같은 특징을 가지고 있다.

 

  • 페이지가 로딩된 이후에는 유저와 상호작용이 빠르다. 특히 url를 변경하는 과정에서 서버단에 새로운 페이지 파일을 요청하지 않고 부드럽게 화면 전환이 가능하다.
  • 서버는 유저에게 전체 페이지 파일을 보내기만 하면 되므로, 역할이 간소화되고 연산 비용이 감소한다.
  • 무거운 자바스크립트 파일을 받아서 실행해야 페이지가 보이기 때문에, 최소 로딩 시간이 길다.
  • 자바스크립트가 제대로 작동하지 않는 일부 구형 브라우저에서 문제가 발생한다.
  • 페이지 소스가 비어 있어서 SEO에 취약하다.

 

CSR은 유저와의 상호작용에서 뛰어나지만, 위와 같은 단점을 가지고 있다. 이런 상황에서 nextJS는 pre-render 방식과 여러 기법으로 이런 단점을 상쇄할 수 있다.

 

 

2. pre-render(static)

prerender는 서버단에서 jsx 컴포넌트와 초기 state를 빌드하여 정적 파일(html, css)로 전환하는 방법이다. nextJS는 기본적으로 빌드 때 prerendering이 이뤄진다. 실시간으로 받아야 하는 데이터는 서버단이나 클라이언트에서 받아 별도로 ui에 반영한다. 

 

참고: hydration
prerender된 정적 html에서 리엑트를 통해 동적 컴포넌트로 전환하는 과정이다. 이 과정을 거치면, html화된 정적인 데이터들이 react의 state로 오버라이드 된다.
nextJS의 jsx 컴포넌트는 서버단과 클라이언트단에서 각각 실행되어 hydration이 이뤄진다. 따라서, localstorage나 dom api처럼 서버단에서 실행될 수 없는 브라우저 api가 포함된 코드는 클라이언트 측에서만 실행되도록 처리해야 한다. 대표적으로 useEffect 에 코드를 두는 방법이 있다. useEffect는 브라우저단에서 마운트된 이후에만 실행되기 때문이다.

 

이처럼, 빌드 타임 때 미리 렌더링 작업이 이뤄지고 정적 컴포넌트를 캐싱하면, 유저는 페이지를 요청할 시 미리 완성된 기본 ui를 보기 때문에 이탈할 가능성이 줄어든다. 데이터 패치가 필요한 부분은 기존의 CSR처럼 클라이언트단에서 데이터를 받아오면 된다.

(주의할 점, dev 모드에서는 코드가 항상 요청마다 서버에서 재실행됨)

 

 

4. SSR(getServersideProps)

CSR, SSR, SSG의 차이점은 여러가지가 있겠지만, 핵심은 데이터 패칭이 이뤄지는 시점이다. 즉, 유저가 페이지를 요청할 시,  pre-render된 ui에 데이터가 들어오는 시점은 언제인가?

 

1) CSR

  • 유저가 페이지를 요청하면, 클라이언트단에서 정적파일과 js파일이 다운로드되고 실행된 시점에 데이터 패칭이 시작된다.
  • 서버의 작업 비용이 줄어든다.
  • 작업이 신속하게 이뤄지지 못하면, 유저는 기본 ui밖에 보지 못한다.

 

2) SSR

  • 유저가 페이지를 요청하면 유저에게 응답을 보내기 전에 서버단에서 먼저 데이터 패칭을 시작한다.
  • 유저는 서버단에서 데이터 패칭과 렌더링이 끝난 파일을 받는다. 따라서 처음부터 완성된 페이지를 볼 수 있다.
  • SEO에 유리하다.
  • 서버의 작업 비용이 증가한다.
  • 작업이 신속하게 이뤄지지 못하면, 유저는 불완전한 페이지 조차 보지 못한다. 따라서, 어떻게 보면 느린 CSR보다도 부정적인 경험을 가져올 수 있다.

 

nextJS의 page Router에서는 getServersideProps 기능을 이용해서 SSR을 할 수 있다. 방법은 아래의 링크를 참조하자.

 

 

4. SSG(getStaticProps)

SSG는 static site generation(정적 사이트 생성)의 약자다. 이 방식은 빌드 시점에만 데이터를 패칭한다. 이는 유저의 요청이나 서버의 요청 때마다 잦은 데이터 요청을 하는 CSR이나 SSR과는 대조적이다.  SSG는 다음 특징을 가진다.

 

  • 빌드 시점에 패칭이 이뤄지므로 유저는 다음 빌드가 이뤄지기 전까지는 최신 데이터가 반영된 페이지를 볼 수 없다.
  • 유저가 페이지를 요청하면, 데이터 패칭이 사전에 완성된 페이지를 가져오므로 작업 속도가 무척 빠르다
  • SEO에 유리하다.

 

SSG는 서버사이드의 장점인 SEO나 빠른 최초 렌더링, 그리고 CSR의 장점인 서버 연산비용 감소를 가지고 있다. 하지만, 자주 변동되는 데이터나 개인 맞춤형 데이터(유저 프로파일)처럼 동적인 데이터에는 사용할 수 없다. 따라서, FAQ나 블로그 포스트처럼 정적인 데이터에 사용하기 적합하다.

 

 

5. ISR(getStaticProps)

ISR(Incremetal Site Regeneration)은 SSG의 단점을 해결하는 한가지 방법으로서, SSG 프로젝트에서  빌드가 주기적으로 이뤄지도록 설정하거나 데이터가 변경되는 상황에만 빌드가 이뤄지도록 설정가능하다. 예컨대, 10분마다 빌드가 다시 이뤄지도록 한다면 최신 데이터를 10분마다 반영할 수 있다. 또한, 유저가 데이터를 추가하거나 수정, 삭제할 때 빌드가 이뤄지록 설정해도 동일한 이점을 얻을 수 있다.

하지만, 이런 식으로 할 때 생기는 문제는, 매 빌드마다 수십 개, 어쩌면 수천 개의 페이지 파일을 재생성하며 많은 시간이나 비용이 소모될 수 있다. 이럴 때를 위해 nextJS는 getStaticPath라는 기능에 fallback 이라는 옵션이 있는데, 이 기능을 이용하면 빌드 타임 때 한꺼번에 모든 사이트가 재생성되는 것이 아니라, 유저가 요청할 때만 빌드되도록 할 수 있다.