사전 서버 사이드 렌더링
개념

서버 사이드 렌더링

gabury1

브라우저에 보일 내용을 서버에서 만들어 보내는 방식입니다. 브라우저는 받은 문서를 거의 그대로 띄웁니다. 자바스크립트는 상호작용을 붙이는 데 씁니다. 내용을 만드는 자리를 브라우저가 아니라 서버로 둔 것입니다.

상세

새로 산 벽시계는 상자를 열면 이미 모양을 다 갖추고 있습니다. 벽에 걸면 그대로 시계로 보입니다. 바늘이 움직이는 것은 받은 사람이 건전지를 끼운 뒤입니다.

서버 사이드 렌더링(Server-Side Rendering, SSR)은 HTML(HyperText Markup Language, 하이퍼텍스트 마크업 언어) 내용을 서버에서 만들어 클라이언트로 보내는 일을 가리킵니다. 반대편에는 클라이언트 사이드 렌더링이 있습니다. 클라이언트가 자바스크립트로 HTML 내용을 만드는 쪽입니다. 두 기법이 서로 배타적이지는 않습니다. 같은 애플리케이션 안에서 함께 쓸 수 있습니다.

내용이 실시간으로 갱신되거나 사용자마다 다른 사이트에서는 요청마다 서버가 그 자리에서 HTML 내용을 만듭니다. 가능한 페이지를 전부 미리 만들어 두는 것이 현실적이지 않기 때문입니다. 이렇게 나온 HTML 파일은 페이지 내용을 거의 완전한 형태로 담습니다. 자바스크립트 자산은 상호작용을 붙이는 몫만 맡습니다.

sequenceDiagram
    participant 브라우저
    participant 서버
    participant 데이터
    브라우저->>서버: 페이지 요청
    서버->>데이터: 필요한 데이터 조회
    데이터-->>서버: 결과
    Note over 서버: HTML 생성
    서버-->>브라우저: HTML 문서

브라우저가 페이지로 이동하면 서버가 그 이동에 대한 응답으로 페이지의 완전한 HTML 을 만들어 냅니다. 데이터를 가져오는 일과 템플릿을 처리하는 일을 렌더러가 먼저 끝냅니다. 브라우저가 응답을 받기 전입니다. 그래서 그 두 가지를 클라이언트에서 하려고 왕복을 더 도는 일이 없습니다.

배경

클라이언트에서 자바스크립트로 화면을 만들면 서버가 내보내는 문서에 실제 내용이 들어 있지 않습니다. 내용은 브라우저에서 자바스크립트가 만들어 냅니다. 그래서 자바스크립트가 돌지 않는 자리에서는 페이지가 비어 보입니다. 인터넷이 느릴 때, 사용자가 자바스크립트를 꺼 뒀을 때, 브라우저가 낡아 자바스크립트 실행이 실패할 때가 그렇습니다. 크롤러도 걸립니다. 주요 검색 엔진은 자바스크립트를 실행할 수 있어서 순수 클라이언트 사이드 렌더링 사이트도 색인될 수 있습니다. 다만 소셜 미디어 크롤러는 대개 실행하지 못합니다. 요청이 폭포처럼 이어지는 일도 잦습니다. 클라이언트는 첫 페이지를 렌더하고 나서야 그다음에 무엇이 더 필요한지 알게 되는 경우가 많기 때문입니다.

만드는 자리를 서버로 옮기면 세 가지가 같이 달라집니다. 성능 쪽에서는 서버가 어떤 내용이 필요한지 미리 알 수 있어서 필요한 데이터를 한 번에 가져올 수 있습니다. 페이지 로직과 렌더링을 서버에서 돌리면 클라이언트로 자바스크립트를 많이 보내는 일을 피할 수 있습니다. 이것이 페이지의 총 차단 시간(Total Blocking Time, TBT)을 줄이는 데 도움이 됩니다. 총 차단 시간이 줄면 다음 페인트까지의 상호작용(Interaction to Next Paint, INP)도 낮아질 수 있습니다. 페이지를 불러오는 동안 메인 스레드가 덜 막히기 때문입니다. 접근성 쪽에서는 자바스크립트 없이도 페이지를 어느 정도 쓸 수 있습니다. 다만 상호작용이나 클라이언트 쪽 로직은 동작하지 않습니다. 크롤러 쪽에서는 검색 엔진과 소셜 미디어 봇이 자바스크립트를 실행하지 않고도 내용을 읽습니다.

이 갈라짐에 이름이 붙었습니다. 서버에서 앱을 렌더해 자바스크립트가 아니라 HTML 을 클라이언트로 보내는 것이 서버 사이드 렌더링입니다. 브라우저에서 자바스크립트로 DOM(Document Object Model, 문서 객체 모델)을 고쳐 렌더하는 것이 클라이언트 사이드 렌더링입니다. 서버 쪽으로 두면 요청한 내용이 눈에 보이기 시작하는 시점인 첫 콘텐츠풀 페인트(First Contentful Paint, FCP)까지의 시간이 대체로 짧게 나옵니다. 대신 서버에서 페이지를 만드는 데 시간이 듭니다. 링크를 클릭한 뒤 새 페이지의 첫 바이트가 도착하기까지의 시간인 첫 바이트까지의 시간(Time To First Byte, TTFB)이 늘어날 수 있습니다.

예시

renderToString 호출

JavaScript
import { renderToString } from 'react-dom/server';
const html = renderToString(<App />);

React 의 서버용 호출입니다. 서버에서 이 호출로 앱을 HTML 로 렌더합니다. 인자는 HTML 로 렌더할 React 노드 하나입니다. <App /> 같은 JSX(JavaScript XML) 노드가 그것입니다. 반환값은 HTML 문자열입니다. 클라이언트에서는 hydrateRoot 를 불러야 서버가 만든 HTML 이 상호작용하게 됩니다.

이 호출에는 제약이 붙습니다. Suspense 지원이 제한적이라 컴포넌트가 중단되면 그 폴백을 곧바로 HTML 로 내보냅니다. 스트리밍도, 데이터를 기다리는 것도 지원하지 않습니다. React 문서는 그럴 때 Node.js 에서는 renderToPipeableStream 을, 웹 스트림에서는 renderToReadableStream 을 쓸 것을 권합니다.

getServerSideProps 내보내기

TypeScript
export const getServerSideProps = (async () => {
  // fetch data from external api
  const res = await fetch('https://api.github.com/repos/vercel/next.js')
  const repo: Repo = await res.json()
  // pass data to the page via props
  return { props: { repo } }
}) satisfies GetServerSideProps<{ repo: Repo }>

Next.js 의 함수입니다. 데이터를 가져와 요청 시점에 페이지 내용을 렌더하는 데 씁니다. 페이지 컴포넌트에서 이 이름으로 내보내면 그 페이지에 걸립니다. 바깥 API(Application Programming Interface, 응용 프로그래밍 인터페이스)에서 받아온 값을 props 로 넘기면 페이지가 그 값으로 렌더됩니다. 빌드 시점이 아니라 요청 시점이라는 것이 이 함수가 서버 사이드 렌더링 자리에 서는 이유입니다.

경계

빌드 때 만들어 둔 정적 사이트도 서버 사이드 렌더링인가. 그렇게 볼 수 있습니다. 서버 사이드 렌더링 인프라로 만들어 낼 수도 있습니다. 다만 뉘앙스 차이가 있습니다. 정적 사이트의 내용은 요청 시점이 아니라 빌드 시점에 만들어집니다. 정적 사이트는 아예 서버에 배포할 필요가 없는 경우가 많습니다. CDN(Content Delivery Network, 콘텐츠 전송 네트워크)에서 그대로 내보낼 수 있습니다.

근거는 서버 쪽 로직의 유무입니다. 정적 사이트 생성기(Static Site Generator, SSG)가 만들어 내는 정적 웹사이트는 HTML 과 CSS(Cascading Style Sheets, 종속형 시트)와 자바스크립트 파일로 이루어집니다. 서버 쪽 로직을 갖지 않으므로 주어진 URL(Uniform Resource Locator, 통합 자원 위치 지정자) 하나에 대해 모든 사용자가 같은 내용을 받습니다. 요청마다 달라질 것이 없으면 만드는 자리를 따지는 일 자체가 흐려집니다. 서버 사이드 렌더링과 클라이언트 사이드 렌더링의 구분은 실시간으로 갱신되거나 사용자마다 다른 내용을 가진 동적 사이트에서 더 의미가 있습니다.

관련 항목

렌더링 위치로 갈리는 방식·아키텍처

렌더링 · 클라이언트 사이드 렌더링 · 정적 사이트 생성기 · 프리렌더링 · 하이브리드 렌더링 · 단일 페이지 애플리케이션 · Jamstack

위에 얹히는 React 확장 기능

서버 컴포넌트 · 서버 함수 · use client · use server

뒤에 필요한 처리 단계

하이드레이션 · 리하이드레이션 · hydrateRoot

예시 코드에 쓰이는 개념·문법

JSX · XML · 노드 · API · Suspense

실제로 구현·채택한 제품

React · Next.js · Nuxt · Node.js

배포·전달되는 경로

배포 · CDN · 네트워크

관여하는 역할·참여자

크롤러 · 검색 · 브라우저

좋아지는 성질과 지표

성능 · 접근성 · 첫 콘텐츠풀 페인트 · 첫 바이트까지의 시간 · 총 차단 시간 · 다음 페인트까지의 상호작용

페이지를 이루는 기본 기술

HTML · CSS · 자바스크립트 · DOM

다른 이름: server-side rendering · SSR · 서버사이드 렌더링