첫 바이트가 가장 느린 데이터에 묶이지 않게 해
스트리밍이 없으면 서버는 페이지에 필요한 모든 데이터가 준비될 때까지 HTML의 첫 바이트도 보내지 못해. 스트리밍을 쓰면 공통 셸과 빠른 부분을 먼저 보내고, 느린 컴포넌트는 데이터가 풀리는 순서대로 뒤이어 보낼 수 있어.
| 방법 | 경계의 크기 |
|---|---|
loading.tsx | 라우트 구간 전체를 프레임워크가 Suspense로 감싸. |
<Suspense fallback> | 개발자가 고른 컴포넌트 하나씩 독립적으로 스트리밍해. |
사용자는 완성 순서대로 화면을 받아
페이지 헤더와 내비게이션은 곧바로 보이고, 느린 차트 자리에는 skeleton이 나타나. 차트 데이터가 도착하면 그 자리만 실제 내용으로 바뀌어. 위쪽 화면을 다시 렌더링하거나 전체 페이지 spinner로 가릴 필요가 없어.
경계를 너무 잘게 쪼개지는 마
모든 작은 컴포넌트에 fallback을 넣으면 화면이 조각조각 깜빡이고 레이아웃이 흔들릴 수 있어. 함께 이해되는 정보는 함께 도착하게 묶고, 실제 지연 원인이 다른 영역 사이에 경계를 둬.
페이지를 사용자가 이해하는 덩어리로 나누고, 실제 지연 시간이 다른 덩어리 사이에 Suspense를 둬. fallback은 최종 크기와 비슷하게 만들어 레이아웃 이동을 막고, 중요한 제목과 행동은 느린 차트 뒤에 숨기지 마. 느린 네트워크에서 도착 순서를 직접 녹화해 보면 경계가 맞는지 보여.
스트리밍은 느린 query를 빠르게 만들지 않아. 기다림을 더 유용하게 보이게 할 뿐이야. 같은 데이터 폭포와 비싼 계산을 그대로 둔 채 skeleton만 늘리면 서버 비용과 완성 시간은 변하지 않아. 원인 최적화와 지각 성능을 별개로 측정해. 느린 경계를 나눌 때는 가장 먼저 의미 있는 내용을 어디까지 보여 줄지도 정해. 대체 화면이 많아도 사용자가 무엇을 기다리는지 모르면 스트리밍의 이점이 사라져. header·목록·느린 chart에 서로 다른 지연을 넣고 route loading.tsx 하나와 컴포넌트 Suspense 여러 개를 비교해. 첫 바이트, 각 영역 도착, 전체 완료 시간을 기록하고 skeleton 크기가 실제 콘텐츠와 달라 CLS를 만드는지도 확인해.
보조 기술에도 loading 상태가 전달되게 aria-busy와 이해 가능한 대체 문구를 검토해. 시각적 skeleton만 움직이고 화면 읽기 도구에는 아무 변화가 없으면 스트리밍 경험이 사용자마다 달라져.