노트

스트리밍 SSR

Streaming Server-Side Rendering

프런트엔드#nextjs#react · 연결된 개념 14개

쉽게 말하면

스트리밍 SSR은 코스 요리처럼 준비된 접시부터 먼저 내고, 오래 걸리는 요리는 다 되는 대로 이어서 내오는 방식이에요. 가장 느린 요리 하나 때문에 손님이 빈 테이블 앞에서 기다리지 않아도 되죠.

비유가 깨지는 곳 이미 낸 접시를 무를 수 없듯, 먼저 보낸 HTTP 상태 코드와 헤더는 나중에 못 바꿔요. 나누는 단위는 Suspense 경계이고, 경계마다 JS가 오는 대로 따로 하이드레이션돼요.

스트리밍 SSR(Streaming Server-Side Rendering)은 서버가 페이지 전체를 다 만들 때까지 기다리지 않고, 준비된 부분의 HTML(HyperText Markup Language)부터 먼저 보내고 느린 부분은 준비되는 대로 같은 응답에 이어서 흘려보내는 렌더링 방식이다. Suspense 경계가 나눔의 단위다.

통짜 SSR의 폭포수

사용자 100ms → 상품 200ms → 추천 3000ms → HTML 생성 → 응답   (3.3초 뒤 첫 바이트)

옛 SSR은 데이터를 다 받아야 HTML을 만들고, JS(JavaScript)를 다 받아야 하이드레이션을 시작하고, 하이드레이션은 한 번 시작하면 멈출 수 없었다. 가장 느린 조각 하나가 전체를 붙잡았다.

스트리밍

<>
  <Header />
  <Suspense fallback={<RecommendSkeleton />}>
    <Recommendations />      {/* 3초 걸리는 서버 컴포넌트 */}
  </Suspense>
  <Footer />
</>
  1. 헤더·푸터와 fallback이 든 HTML을 즉시 보낸다. 사용자는 바로 페이지를 본다
  2. 추천 데이터가 준비되면 그 영역의 HTML과 교체용 스크립트를 같은 연결로 이어 보낸다
  3. 경계마다 JS가 오는 대로 따로 하이드레이션된다
  • Next.js App Router는 기본으로 스트리밍한다. loading.tsx는 페이지를 Suspense로 감싸는 단축 문법이다
  • 흐르는 것은 HTML만이 아니라 RSC 페이로드도 포함한다. 서버가 넘긴 Promise를 클라이언트에서 use()로 읽는 것도 이 위에서 동작한다
  • 첫 바이트가 빨라지는 대신, 이미 보낸 HTTP(HyperText Transfer Protocol) 상태 코드와 헤더는 나중에 바꿀 수 없다
  • 정적 셸과 스트리밍을 합친 것이 부분 사전 렌더링(PPR)이다. 렌더링 방식 비교는 CSR·SSR·SSG·ISR, 사용자 체감 지표는 Core Web Vitals

연결된 개념

이 노트를 가리키는 문서

뜻이 가까운 노트

  • 브라우저 렌더링 파이프라인

    브라우저가 받은 HTML·CSS·JS를 화면의 픽셀로 바꾸는 순서. 처음 로드할 때도, 이후 무언가 바뀔 때도 같은 단계를 거친다. 바뀐 내용에 따라 어느 단계부터 다시 시작하는지만 다르다.

  • CSR bailout

    CSR(Client-Side Rendering) bailout은 미리 렌더(Prerender)되는 라우트에서 서버가 알 수 없는 값을 읽는 클라이언트 컴포넌트를 만나, 가장 가까운 Suspense 경계까지의 클라이언트 컴포넌트 트리를 서버 렌더에서 포기하고 브라우저 렌더로 넘기는 일이다. 대표 원인이 useSearchParams()다. 빌드 때는 ?q=신발 같은 쿼리를 모르기 때문이다.

  • 서버 렌더에서 훅이 하는 일

    서버 렌더(Server-Side Rendering, SSR)에서도 컴포넌트 함수는 실제로 호출되고, 그 안의 훅도 호출은 된다. 다만 서버에는 커밋(DOM 반영)이 없어서, 렌더 중 동기적으로 값을 계산하는 훅만 일하고 커밋 뒤에 도는 훅은 아무것도 하지 않는다. "이 훅은 클라이언트에서만 동작한다"는 말은 대개 "Effect 안의 일은 클라이언트에서만 일어난다"는 뜻이다.

  • XSS

    XSS(Cross-Site Scripting)는 공격자가 넣은 스크립트가 내 사이트의 출처(origin) 권한으로 사용자 브라우저에서 실행되는 공격이다. 같은 출처의 코드로 돌기 때문에 same-origin-policy가 막아 주지 못한다. 그 스크립트는 페이지를 바꾸고, 로그인한 사용자 행세를 하며 요청을 보내고, JS가 읽을 수 있는 데이터(localStorage의 토큰 등)를 빼 갈 수 있다.

보기 옵션