본문 바로가기

Study/NextJS 공식문서

[5주 차] Server Components

Server Components을 이용한 서버 랜더링의 이점

데이터 페칭: Server Componets를 사용하면 데이터 페칭을 서버에서 수행할 수 있다. 이렇게 하면 렌더링에 필요한 데이터를 가져오는 데 걸리는 시간과 클라이언트가 해야 하는 요청 수를 줄여 성능을 개선할 수 있다.

보안: Server Componets를 사용하면 토큰과 API 키 같은 중요한 데이터와 로직을 클라이언트에 노출시키지 않고 서버에 보관할 수 있다. 이를 통해 보안 위험을 줄일 수 있다.

캐싱: 서버에서 렌더링하면 결과를 캐싱하여 후속 요청과 사용자 간에 재사용할 수 있다. 이렇게 하면 각 요청에서 수행되는 렌더링 및 데이터 페칭 양을 줄여 성능을 개선하고 비용을 절감할 수 있다.

성능: UI의 비대화형 부분을 Server Componets로 이동하면 필요한 클라이언트 측 JavaScript 양을 줄일 수 있다. 이는 브라우저가 다운로드, 구문 분석 및 실행할 클라이언트 측 JavaScript가 적기 때문에 클라이언트 기기의 부담을 덜어준다.

초기 페이지 로드 및 첫 번째 콘텐츠 페인트(FCP): 서버에서는 클라이언트가 페이지를 렌더링하는 데 필요한 JavaScript를 다운로드, 구문 분석하고 실행할 때까지 기다리지 않고도 사용자가 페이지를 즉시 볼 수 있도록 HTML을 생성할 수 있다.

검색 엔진 최적화: 렌더링된 HTML은 검색 엔진 봇이 페이지를 인덱싱하는 데 사용할 수 있으며, 소셜 네트워크 봇은 페이지에 대한 소셜 카드 미리보기를 생성하는 데 사용할 수 있다.

스트리밍: Server Componets를 사용하면 렌더링 작업을 청크로 분할하여 준비되면 클라이언트로 스트리밍할 수 있다. 이를 통해 사용자는 서버에서 전체 페이지가 렌더링될 때까지 기다릴 필요 없이 페이지의 일부를 더 일찍 볼 수 있다.

 

NextJS에서의 Server Components

NextJS에서는 기본적으로 Server Components를 사용하여 서버 렌더링을 자동으로 구현할 수 있다. 필요에 따라 Client Components를 선택적으로 사용할 수 있으며, Client Components를 정의하려면 해당 파일의 최상단에 "use client" 지시어를 추가하면 된다.

 

How are NextJS rendered?

NextJS는 서버 사이드 렌더링(SSR)과 클라이언트 사이드 렌더링(CSR)의 장점을 결합한 하이브리드 렌더링 방식을 사용한다. 

서버 측에서는 서버 컴포넌트와 클라이언트 컴포넌트를 렌더링하여 HTML 형태의 결과물을 생성한다. 이 과정에서 인라인 스타일과 useState의 초기값과 같은 리액트의 상태 및 생명주기에 영향을 미치지 않으며, 서버에서 결정할 수 있는 요소들이 포함된다. 이러한 과정을 프리렌더링이라고 하며, 생성된 프리랜더링 결과물인 HTML은 CSS 및 JavaScript 파일과 함께 브라우저로 전송된다.

특히, 서버 컴포넌트는 프리렌더링 결과물과 함께 클라이언트 컴포넌트가 렌더링될 위치, 해당 JavaScript 파일에 대한 참조, 그리고 서버 컴포넌트에서 클라이언트 컴포넌트로 전달된 모든 props를 포함하는 간결한 이진 표현인 React Server Component Payload(RSC Payload)를 생성하여 브라우저에 전달한다.

클라이언트 측은 서버로부터 전달된 프리렌더링된 HTML을 우선 로드한다. 그 후, 해당 HTML에 포함되지 않은 CSS와 JavaScript 파일들을 다운로드한다. 이렇게 함으로써 사용자는 초기 콘텐츠를 빠르게 확인할 수 있어 사용자 경험이 향상된다.

JavaScript 파일이 로드되면, 클라이언트 측에서 초기 렌더링이 시작된다. 이 과정에서 프리렌더링된 HTML과 RSC Payload를 이용하여 React의 가상 DOM을 비교, 필요한 부분을 업데이트하고 이벤트 리스너와 상태 관리 기능을 활성화한다. 이러한 과정을 하이드레이션(Hydration)이라고 한다.

만약 하이드레이션 과정에서 프리랜더링 결과물(HTML)과 가상 DOM 간의 불일치가 발생하면 하이드레이션 오류가 발생할 수 있다. 하이드레이션이 완료되면, onClick이나 useEffect와 같은 기능들이 활성화되어 클라이언트 측에서의 상호작용이 가능해진다. 이 시점부터는 window나 localStorage와 같은 브라우저 전용 객체를 사용할 수 있다.

이후 클라이언트 측 네비게이션을 통해 이동할 때는전체 페이지를 다시 로드하지 않고 클라이언트 측에서 필요한 부분만 업데이트 한다. 이 과정에서 클라이언트는 필요한 JavaScript 번들을 다운로드하고 파싱한다. 준비가 완료되면 서버로부터 전달된 RSC Payload를 사용하여 서버와 클라이언트 컴포넌트 트리를 조정하고 DOM을 업데이트한다.

 

Server Rendering Strategies

NextJS는 서버 렌더링을 위한 세 가지 전략 정적 렌더링(Static Rendering, SSG, ISR), 동적 렌더링(Dynamic Rendering, SSR), 그리고 스트리밍(Streaming)을 제공한다.

정적 렌더링은 빌드 시점에 페이지를 렌더링하여 결과를 캐시하고, 이를 CDN(Content Delivery Network)을 통해 제공하는 방식이다. 이 접근 방식은 사용자별로 변경되지 않는 콘텐츠에 적합하며, 블로그 게시물이나 제품 상세 페이지와 같이 빌드 시점에 내용이 확정되는 경우에 유용하다. 정적 렌더링을 통해 여러 사용자와 서버 요청 간에 렌더링 결과를 공유하여 성능을 향상시킬 수 있다. Data Revalidation 설정에 따라서 SSG와 ISR로 나뉜다.

동적 렌더링은 각 사용자 요청 시점에 페이지를 렌더링하는 방식이다. 사용자별로 개인화된 데이터나 요청 시점에만 알 수 있는 정보를 포함해야 하는 페이지에 적합하다. 예를 들어, 사용자 쿠키나 URL의 검색 매개변수에 따라 내용이 달라지는 경우 동적 렌더링이 필요하다.

NextJS는 사용된 기능과 API에 따라 각 경로에 가장 적합한 렌더링 전략을 자동으로 선택한다. 따라서, 개발자가 특정 경로를 정적 렌더링(SSG 또는 ISR)으로 설정하더라도, 해당 경로에서 동적 함수(예: cookies(), headers(), searchParams 등)를 사용하거나 캐시되지 않은 데이터를 요청하면, Next.js는 해당 경로를 자동으로 동적 렌더링(SSR)으로 전환한다.

NextJS에서는 서버에서 UI를 점진적으로 렌더링하여 준비된 부분부터 클라이언트로 스트리밍할 수 있다. 이를 통해 사용자는 전체 콘텐츠가 렌더링되기 전에 페이지의 일부를 즉시 볼 수 있어 초기 로딩 시간을 단축하고 사용자 경험을 향상시킬 수 있다. 이러한 스트리밍 기능은 React의 Suspense 컴포넌트와 함께 사용되며, Next.js에서는 각 경로(segment) 폴더에 loading.tsx 파일을 추가하여 로딩 상태를 관리할 수 있다.