[NextJS] NextJS 의 렌더링 기법 , CSR, SSR , SSG , ISR

ChoiYongHyeun·2024년 5월 23일
0

NextJS

목록 보기
5/9
post-thumbnail

최근 3개의 docs 에서 NextJS 에서의 라우팅을 공부했는데 그것보다 우선해야 될 개념이 있는 것 같아 먼저 공부토록 하겠습니다.


기존 React Only 렌더링 시의 문제


React 만 사용하여 생성된 웹앱에 클라이언트가 접근했을 때 발생하는 과정은 다음과 같습니다.

  1. 사용자가 웹앱의 루트 라우터에 접속하여 request 요청을 보냄
  2. 사용자는 서버에서 전송한 index.htmlresponse 을 받음
  3. 이 때 index.html<div id = 'root'></div> 만 존재하기 때문에 브라우저에 어떤 화면도 렌더링 되지 않음
  4. 클라이언트는 index.html 에 존재하는 script 태그를 통해 번들로 빌드된 react 코드를 요청하여 받아 실행함
  5. react 코드가 실행되며 Virtual DOM 생성되고 생성된 Virtual DOM 을 이용해 Actual DOM 을 업데이트 함
  6. 페이지에 의미 있는 정보가 렌더링 됨

이렇게 React Only 로 개발된 웹앱은 의미 있는 정보가 처음 렌더링 되는 , 즉 First Contentfull Paint 까지의 시간이 오래 걸립니다.

First Contentfull Paint 가 일어나기 위해서 React 코드를 요청받은 후 클라이언트 상에서 실행까지 일어나야 하기 때문입니다.

또, 만약 첫 / 경로까지의 렌더링만이 필요하더라도 lazy loading 을 사용하지 않았을 경우 모든 페이지의 react code 가 실행되기 전까지 / 페이지가 렌더링 되지 않습니다.

또 , html 파일에는 단순히 <div id = 'root'> 만 존재하기 때문에 검색 엔진 알고리즘에서 html 파일의 구조를 통해 판단하는 SEO 가 최적화되지 않아

SEO 최적화가 힘들다는 단점이 존재합니다.

정리

React Only 시에는 FCP 까지 기간이 오래 걸리고 번들 사이즈가 클 수록 FCP 가 증가합니다.
그리고 html 문서가 단순하기 때문에 SEO 최적화가 어렵다는 단점이 존재합니다.

NextJS 에서 선택한 렌더링 전략


이에 NextJS 는 다음과 같은 렌더링 전략을 택했습니다.

  • CSR (Client Side Rendering) 은 FCP 까지의 기간이 오래 걸리기 때문에 SSR (Server Side Rendering) 기법을 이용하자

즉, 클라이언트 측에시 실행되어야 하는 코드를 서버 측에서 실행하여 html 문서를 생성하고 사용자가 요청하면 html 문서를 제공합니다.

SSR 을 사용하면 얻는 이점들은 다음과 같이 존재합니다.

  • 단순한 html 문서만을 전송하기 때문에 FCP 까지 걸리는 시간이 짧습니다.
  • html 문서는 용량이 적기 때문에, 클라이언트 근처의 CDN (Content Delivery Network) 에 캐싱해둘 수 있습니다.
  • 페이지가 html 로 이뤄져있기 때문에 SEO 최적화가 수월합니다.

사실 여기까지만 들으면 CSR 기법이 등장하기 전하고 뭐가 다른지 이해가 잘 되지 않습니다.

그럼 그냥 React 를 이용해서 서버측에서 html 문서를 만들어두고 보내는거 아닌가 ? CSR 이 등장하기 전 SSR 기법 때와 뭐가 다른지 잘 이해가 가지 않습니다.

오히려 기술이 발전한게 아니라 과거로 회귀한게 아닌가 ? 하는 생각이 듭니다.

SSR 만 이용 할 때의 문제

SSR 에서 CSR 기법으로 트렌드가 넘어가게 되었던 계기 중 하나는 다음과 같은 문제였습니다.

잦은 인터렉티브로 인해 페이지가 변경될 때 마다 html 문서를 새로 받아와 블링크 현상이 발생하여 UX 가 낮아진다.

SSR 은 사용자의 request 가 있을 때, request 에 맞는 html 문서를 생성하고 사용자에게 response 를 보내는 기법입니다.

인터렉티브한 효과가 불가능하진 않았지만, 각 인터렉션 별로 매번 html 문서를 만들고 보내줬기에 전체 페이지가 다시 받아져 깜박이는 현상인 Blink 가 발생했습니다.

그래서 전체 페이지를 생성하는 SSR 보다 , 변경된 페이지만 클라이언트 단에서 조작하는 CSR 기법이 UX 가 더 높다! 라는 트렌드가 있었습니다.

NextJSSSR , CSR 을 합성하여 사용한다.

이에 NextJS 는 기존의 SSR 기법뿐 아니라,클라이언트 단에서 호출되어야 생성되어야 하는 페이지는 클라이언트 단에서 생성하는 Composition SSR, CSR 을 이용합니다.

인터렉션에 의해 변경되어야 하는 페이지란 무엇이 있을까요 ?

  • state 가 존재하며 변경되는 state 에 따라 렌더링 되는 화면이 달라져야 하는 페이지
  • windowAPI 를 사용해야 하는 페이지
  • Actual DOM 에 접근해야 하는 페이지 (onClick 과 같은 이벤트 핸들러 부착)

다음과 같은 경우들이 클라이언트 단에서 생성되어야 하는 페이지들입니다.

하지만 모든 페이지들 전체가 정적이거나 , 동적일 필요는 없습니다.

페이지의 상단 네비게이션 바 같은 경우엔 동적인 렌더링이 필요가 없지만 , 내부의 콘텐츠들은 동적인 렌더링이 필요 할 수 있습니다.

이에 SSR , CSR 을 페이지라는 큰 하나의 개념에서만 사용하는 것이 아닌, 컴포넌트 단위로 분할하여 사용합니다.

즉 , NextJS 는 서버 단에서 생성되는 것이 더 효과적인 정적 컴포넌트인 서버 컴포넌트 와 클라이언트 단에서 생성되는 것이 더 효과적인 클라이언트 컴포넌트 , 이 둘을 합성하여 페이지를 생성합니다.

이렇게 서버 컴포넌트, 클라이언트 컴포넌트를 이용하여 서버 측에서 먼저 렌더링하여 완성된 html 문서를 생성하고 클라이언트에게 전송합니다.

이 때 생성된 html 은 아직 클라이언트 컴포넌트에 의한 동적인 기능이 부착되어 있지 않습니다.

클라이언트 컴포넌트의 hydrate

서버 단에서 생성된 html 은 클라이언트 컴포넌트도 포함되어 생성된 문서이지만 아직 클라이언트 컴포넌트의 기능이 부착되어 있지 않습니다.

서버 단에서 렌더링 될 때엔 Virtual DOMwindow API , Actual DOM 도 존재하지 않는 상태이기 때문입니다.

이에 클라이언트 컴포넌트들은 클라이언트 단에서 한 번 더 렌더링 되며 이를 hydrate 된다고 합니다.

🪢 React 공식 문서의 hyrateRoot

클라이언트 단에서 hydrate 되면서 Virtual DOM 도 생성하고 window API , Actual DOM 에 인터렉션들을 부착합니다.

hydrate 되기 전엔 인터렉션이 불가능합니다.

이를 통해 인터렉티브한 웹앱을 생성하는 것이 가능해집니다.

결국 NextJS 에서도 클라이언트 단에서 렌더링 되는 컴포넌트들이 존재하는 것을 의미합니다.

그렇지만 기존 클라이언트 렌더링과 다른 점은 먼저 완성되어 있는 상태의 페이지를 받은 후, 클라이언트 컴포넌트가 렌더링 되는 것이기 때문에 FCP가 짧다는 모습이 짧습니다.

SSRSSG


정적인 기능만 존재하는 (렌더링에만 집중하는) 컴포넌트들 SSR 을 이용하여 생성한다 했습니다.

사실 NextJS 에선 SSR 뿐 아니라 SSG 도 존재합니다.

  • SSR : Server Side Rendering 의 준말로 클라이언트에 요청이 있을 때 렌더링하여 컴포넌트 생성
  • SSG : Static Site Generation 의 준말로 개발자가 페이지를 빌드 할 때 컴포넌트 생성

SSR 은 클라이언트 요청시마다 렌더링되어 페이지를 생성하는 반면, SSG 는 개발자가 컴포넌트를 빌드 할 때 한 번만 렌더링하여 생성해두고 요청시 마다 생성해둔 컴포넌트를 이용하는 기법입니다.

정적인 컴포넌트들이더라도 어떤 요청시에도 절대 불변하는 컴포넌트가 있을 수 있고 요청 시 마다 변경되는 컴포넌트 등이 존재 할 수 있습니다.

예를 들어 상단의 네비게이션 바같은 경우는 어떤 클라이언트의 요청에든 상관없이 항상 같은 결과물입니다. 이러한 경우는 SSG 를 이용하여 생성합니다.

다른 예시로 사용자가 보낸 쿠키를 통해 사용자를 기억하고 *** 님 반갑습니다. 라는 문구가 상단에 띄우고 싶다고 해봅시다.

이 때는 정적인 컴포넌트이지만 요청 시 마다 다른 결과값을 보여야 합니다. 이러한 경우엔 SSR 을 사용합니다.

정리

NextJS에서 사용하는 렌더링 종류

  • CSR : 동적으로 클라이언트 단에서 생성되어야 하는 클라이언트 컴포넌트를 서버 단에서 렌더링 하여 html 문서 생성 , 클라이언트 단에서 한번 더 렌더링 되어 인터렉티브한 컴포넌트 생성
  • SSR : 정적인 서버 컴포넌트 이지만 클라이언트의 request 에 따라 서버 컴포넌트를 렌더링, 이를 dynamic rendering 이라고도 함
  • SSG : 정적인 서버 컴포넌트 이며 클라이언트의 request 와 상관 없는 정적 컴포넌트를 이용한 렌더링이며 build 타임시 단 한번 렌더링 함

SSGISR


사실 SSG 엔 두 가지 종류가 있습니다.

SSG 는 클라이언트의 request 와 상관없는 독립적인 정적 서버 컴포넌트입니다.

그렇기 때문에 클라이언트의 request 와 상관없이 build 시 한 번만 컴포넌트를 미리 렌더링 해두고 request 마다 항상 동일한 결과를 이용하여 페이지를 생성합니다.

하지만 이런 경우를 생각해봅시다.

저의 웹앱에선 대한민국의 실시간 코스피 지수를 제공합니다.

그렇다면 대한민국 실시간 코스피 지수는 클라이언트의 request 와 독립적인 정보이기 때문에 SSG 를 이용해 만들 수 있습니다.

하지만 SSGbuild 타임에 딱 한번 빌드 되기 때문에 실시간으로 정보를 제공하기 위해선 정해진 간격 마다 build 를 해줘야 합니다.

이는 비효율적이기에 ISR 이란 개념이 등장했습니다.

ISR (Incremental Static Regeneration) 이란 이름에서 볼 수 있듯이 정해둔 어떤 간격마다 Static siteRe-generation 합니다.

ISR 은 정해둔 interval 마다 Static site 를 재생성합니다.

즉, request 와 상관 없지만 어떤 간격마다 새로운 정보를 담아야 하는 static site 를 만들 때 사용하는 것이 ISR 입니다.

profile
빨리 가는 유일한 방법은 제대로 가는 것이다

0개의 댓글