|
| 1 | +# CHAPTER 13 렌더링 패턴 |
| 2 | + |
| 3 | +## 렌더링 패턴의 중요성 |
| 4 | + |
| 5 | +크롬 팀은 페이지 전체를 하이드레이션 하는 방식보다 정적 렌더링 또는 SSR 사용을 권장 |
| 6 | + |
| 7 | +## 클라이언트 사이드 렌더링(CSR) |
| 8 | + |
| 9 | +거의 모든 UI가 클라이언트에서 생성되고, 처음 요청 시에 전체 웹 애플리케이션 모두 로드 |
| 10 | +페이지의 복잡성이 증가하면 페이지 렌더링에 필요한 자바스크립트 코드의 복잡성과 크기도 증가 |
| 11 | +크롤러가 색인하기 전에 의미 있는 콘텐츠가 시간에 맞춰 렌더링되지 않을 수 있어 SEO에 불리 |
| 12 | + |
| 13 | +## 서버 사이드 렌더링(SSR) |
| 14 | + |
| 15 | +모든 요청마다 HTML 생성 |
| 16 | +데이터 fetching을 위한 추가적인 왕복 시간을 줄일 수 있음 |
| 17 | +HTML을 서버에서 렌더링하고 클라이언트에서 다시 하이드레이션하는 데 필요한 자바스크립트를 함께 제공하는 것이 핵심 |
| 18 | +하이드레이션에는 비용이 따르기 때문에 SSR은 하이드레이션 과정을 최적화하려고 함 |
| 19 | + |
| 20 | +### 적합한 경우 |
| 21 | + |
| 22 | +- 사용자 쿠키 정보나 요청 데이터를 기반으로 하는 등 **개인 맞춤형 데이터를 포함하는 페이지** |
| 23 | +- 인증 상태에 따라 렌더링 여부를 결정해야 하는 페이지 |
| 24 | +- 개인화된 대시보드 |
| 25 | + |
| 26 | +## 정적 렌더링 |
| 27 | + |
| 28 | +전체 페이지의 HTML을 빌드 시점에 미리 생성해 다음 빌드 때까지 변경되지 않는 것 |
| 29 | +정적인 HTML 콘텐츠는 CDN이나 엣지 네트워크에 쉽게 캐싱됨 |
| 30 | + |
| 31 | +### 적합한 경우 |
| 32 | + |
| 33 | +- **자주 변경되지 않고, 누가 요청하든 동일한 데이터를 표시하는 페이지** |
| 34 | +- 회사 소개, 문의하기, 블로그 페이지 |
| 35 | +- 전자상거래 애플리케이션의 상품 페이지 |
| 36 | + |
| 37 | +### Next.js도 정적 생성을 지원하는 프레임워크 중 하나 |
| 38 | + |
| 39 | +#### 리스트 페이지 정적 생성 |
| 40 | + |
| 41 | +- Pages Router : `getStaticProps()` |
| 42 | +- App Router : `fetch`의 `cache` 옵션 |
| 43 | + |
| 44 | +#### 동적 경로를 사용한 상세 페이지 정적 생성 |
| 45 | + |
| 46 | +- Pages Router : `getStaticPaths()` |
| 47 | +- App Router : `generateStaticParams()` |
| 48 | + |
| 49 | +#### 클라이언트 사이드 데이터 fetching을 통한 정적 렌더링 (항상 최신 목록을 표시해야 하는 동적인 리스트 페이지) |
| 50 | + |
| 51 | +웹사이트의 UI를 Skeleton 컴포넌트와 함께 정적으로 렌더링 |
| 52 | +동적 목록 데이터를 배치할 위치를 미리 지정 |
| 53 | +페이지가 로드된 후 SWR`/`Tanstack Query를 사용해 데이터를 가져옴 |
| 54 | + |
| 55 | +### 점진적 정적 생성(ISR) |
| 56 | + |
| 57 | +**SSR + 정적 렌더링 = ISR** |
| 58 | + |
| 59 | +특정 정적 페이지만 미리 렌더링하고, 동적 페이지는 사용자 요청 시에 on-demand 방식으로 렌더링 → 빌드 시간 단축 |
| 60 | +**특정 간격마다 캐시를 자동으로 무효화하고 페이지 다시 생성** |
| 61 | +`Stale-While-Revalidate` 전략을 사용해 백그라운드에서 재검증하는 동안 사용자는 캐시된 버전을 봄 |
| 62 | + |
| 63 | +### On-demand ISR |
| 64 | + |
| 65 | +|일반 ISR|On-demand ISR| |
| 66 | +|:-:|:-:| |
| 67 | +|정해진 시간 간격마다 페이지 재생성|특정 이벤트 발생 시에 페이지 재생성| |
| 68 | +|요청을 처리한 엣지 네트워크 노드에만 업데이트된 페이지 캐시|엣지 네트워크 전체에 페이지 재생성, 재분배(모든 사용자가 최신 버전 확인)| |
| 69 | + |
| 70 | +### 정적 렌더링 요약 |
| 71 | + |
| 72 | +- 순수 정적 렌더링 : **동적인 데이터가 없는** 페이지에 적합 |
| 73 | +- 클라이언트 사이드 데이터 fetching을 통한 정적 렌더링 : **로드 시마다 데이터가 새로고침**되어야 하고, **placeholder**를 가진 페이지에 적합 |
| 74 | +- 점진적 정적 생성(ISR): **특정 간격** 또는 필요에 따라 재생성되어야 하는 페이지에 적합 |
| 75 | +- On-demand ISR : **특정 이벤트 발생** 시 재생성되어야 하는 페이지에 적합 |
| 76 | + |
| 77 | +## 스트리밍 SSR |
| 78 | + |
| 79 | +SSR이나 정적 렌더링을 사용하는 것보다 **TTI, FCP 단축 가능** |
| 80 | +현재 페이지에 필요한 마크업을 모두 담은 HTML 하나를 생성하는 대신, **chunk로 나눠서 전송** |
| 81 | +리액트에 내장된 `renderToNodeStream` 함수를 사용하면 애플리케이션을 작은 조각으로 나눠서 전송 가능 |
| 82 | +클라이언트는 **데이터를 받는 동시에 UI를 그리기 시작**할 수 있어 **매우 빠른 초기 로딩 경험 제공** |
| 83 | +이렇게 수신된 DOM 노드에 `hydrate` 메서드를 호출하면, 이벤트 핸들러가 연결되어 상호작용 가능 |
| 84 | + |
| 85 | +## 엣지 SSR |
| 86 | + |
| 87 | +CDN의 모든 지역에서 서버 렌더링 가능, 거의 0에 가까운 콜드 부트 시간(함수가 처음 실행될 때 발생하는 지연 시간) |
| 88 | + |
| 89 | +### 활용 사례 |
| 90 | + |
| 91 | +ex. 지역 특화 리스트 페이지 |
| 92 | +리스트만 외부 요청, 페이지 대부분은 정적 데이터로 구성 |
| 93 | +리스트 컴포넌트만 서버 사이드 렌더링, 나머지는 엣지 사이드에서 렌더링 |
| 94 | + |
| 95 | +## 하이브리드 렌더링 |
| 96 | + |
| 97 | +어떤 상황에서든 최적의 결과를 제공하기 위해 여러 가지 렌더링 방식 결합 |
| 98 | +Next.js는 리액트 서버 컴포넌트와 App Router를 결합해 하이브리드 렌더링 지원 |
| 99 | + |
| 100 | +## 점진적 하이드레이션 |
| 101 | + |
| 102 | +**각 노드를 시간에 따라 개별적으로 하이드레이션하여 필요한 최소한의 JS만 요청하는 방식** |
| 103 | +페이지에서 덜 중요한 부분의 하이드레이션을 지연시켜 JS 양을 줄이고, 사용자에게 필요한 노드만 하이드레이션 |
| 104 | +서버에서 렌더링된 DOM 트리가 파괴되고 즉시 다시 생성되는 SSR의 문제 방지할 수 있음 |
| 105 | +애플리케이션을 여러 조각으로 나누어 뛰어난 성능을 제공하는 것을 목표로 함 |
| 106 | + |
| 107 | +### 완전한 점진적 하이드레이션을 위한 요구사항 |
| 108 | + |
| 109 | +- 모든 컴포넌트에 SSR 사용 가능 |
| 110 | +- 개별 컴포넌트 또는 조각 단위로 코드 스플리팅 지원 |
| 111 | +- 개발자가 정의한 순서대로 클라이언트 사이드에서 각 조각 별 하이드레이션 지원 |
| 112 | +- 이미 하이드레이션된 조각에서 사용자 입력 가능 상태 유지 |
| 113 | +- 지연된 하이드레이션이 적용되는 조각에 로딩 중임을 표시 가능 |
| 114 | + |
| 115 | +리액트의 동시성 모드(concurrent mode) 기능 덕분에 요구사항 충족 |
| 116 | +동시성 모드 = 여러 작업을 동시에 처리하면서도, 우선순위에 따라 작업 전환 가능 |
| 117 | + |
| 118 | +## 아일랜드 아키텍처 |
| 119 | + |
| 120 | +정적인 HTML 위에 독립적으로 전달될 수 있는 상호작용 아일랜드를 통해 JS 전송량을 줄이는 패러다임 |
| 121 | +컴포넌트 기반 아키텍처 |
| 122 | +정적/동적 아일랜드로 구분된 페이지 뷰 제안 |
| 123 | +정적 콘텐츠로 이루어진 페이지의 SSR 지원 |
| 124 | + |
| 125 | +|점진적 하이드레이션|아일랜드 아키텍처| |
| 126 | +|:-:|:-:| |
| 127 | +|하향식 하이드레이션 구조|각 컴포넌트가 자체적으로 하이드레이션 스크립트 가짐| |
| 128 | +|페이지가 개별 컴포넌트의 스케줄링 및 하이드레이션 제어|하이드레이션 스크립트는 페이지의 다른 스크립트와 독립적으로 비동기 실행| |
| 129 | + |
| 130 | +### 장점 |
| 131 | + |
| 132 | +- 성능 : JS 코드의 양이 감소해 페이지 로드 속도 빨라짐 |
| 133 | +- SEO : 모든 정적 콘텐츠가 서버에서 렌더링되므로 SEO에 유리 |
| 134 | +- 중요 콘텐츠 우선순위 |
| 135 | +- 접근성 |
| 136 | +- 컴포넌트 기반 |
| 137 | + |
| 138 | +### 단점 |
| 139 | + |
| 140 | +- 아직 초기 단계라서 사용 가능한 프레임워크가 적고, 직접 아키텍처 개발해야 함 |
| 141 | +- 소셜 미디어 애플리케이션처럼 상호작용을 위주로 한 페이지에는 적합하지 않음 (수천 개의 아일랜드가 필요할 수 있음) |
| 142 | + |
| 143 | +## 리액트 서버 컴포넌트 |
| 144 | + |
| 145 | +서버에서 실행되도록 설계된 컴포넌트로, 상태를 가지지 않음 |
| 146 | +RSC는 번들 크기를 0으로 줄임 → 결과적으로 클라이언트 사이드 JS 번들 크기 감소 |
| 147 | +서버 컴포넌트와 클라이언트 컴포넌트 사이의 매끄러운 코드 전환 경험(knitting) 가능 |
0 commit comments