Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
246 changes: 246 additions & 0 deletions 박영인/Chapter 13 - 렌더링 패턴.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,246 @@
웹 애플리케이션은 정적 콘텐츠와 동적 콘텐츠를 혼합해 제공한다. 정적 콘텐츠는 서버에서 생성된 HTML을 그대로 전달해도 되지만, 버튼·필터·검색창 같은 동적 콘텐츠는 렌더링 후 이벤트와 이어져야 한다.
상황에 맞는 렌더링 패턴을 선택하면 **개발 속도, 운영 비용, 사용자 경험**을 모두 향상시킬 수 있다.

### 주요 렌더링 패턴

| **패턴** | **핵심 설명** |
| ---------------------- | ----------------------------------------- |
| **클라이언트 사이드 렌더링(CSR)** | HTML이 브라우저에서 완전히 렌더링된다. |
| **서버 사이드 렌더링(SSR)** | 서버가 HTML을 동적으로 생성하고, 클라이언트는 하이드레이션을 실행한다. |
| **정적 렌더링(Static)** | 빌드 시점에 서버가 페이지를 미리 렌더링해 정적 사이트를 만든다. |
| **점진적 정적 생성(ISR)** | 빌드 후에도 정적 사이트를 동적으로 추가·수정할 수 있다. |
| **스트리밍 SSR** | 서버가 렌더링된 HTML을 작은 스트림 단위로 전송한다. |
| **엣지 렌더링** | 렌더링된 HTML을 클라이언트에 전달하기 전, 엣지에서 수정한다. |
| **하이브리드 렌더링** | 빌드·서버·클라이언트 렌더링을 조합해 유연성을 제공한다. |
| **부분 하이드레이션** | 클라이언트에서 일부 컴포넌트만 하이드레이션한다. |
| **점진적 하이드레이션** | 클라이언트에서 컴포넌트를 순차적으로 하이드레이션한다. |
| **아일랜드 아키텍처** | 정적 사이트 안에 진입점이 있는 동적 격리 영역을 만든다. |
| **점진적 향상** | 자바스크립트가 없어도 앱이 동작하도록 보장한다. |

### 렌더링 패턴 선택 시 고려해야할 것
- **렌더링 위치**를 정해야 한다: 웹 서버, 빌드 서버, 엣지 네트워크, 클라이언트 중 어디서 HTML을 만들 것인가?
- **렌더링 범위**를 결정한다: 한 번에 모두 렌더링할지, 필요한 부분만 부분적·점진적으로 렌더링할지?

## 13.1 렌더링 패턴의 중요성
올바른 패턴 선택을 하면 이런 이점을 얻을 수 있다:
- **Build 속도**와 **로딩 성능**을 개선
- **서버 비용**을 절감
- 빠른 **롤백**, 안정적인 **가동 시간**, **확장성**을 보장

### 핵심 웹 지표(Core Web Vitals)
- **TTFB**: 클라이언트가 첫 바이트를 받는 시간
- **FCP**: 첫 콘텐츠가 렌더링될 때까지의 시간
- **TTI**: 사용자가 상호작용할 수 있을 때까지의 시간
- **LCP**: 주요 콘텐츠를 완전히 렌더링하는 시간
- **CLS**: 예기치 못한 레이아웃 변화를 측정
- **FID**: 첫 입력 지연

👉 위 CWV를 개선하면 검색 엔진 최적화와 사용자 경험을 동시에 향상시킬 수 있다.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

핵심 지표 절대 지켜~




## 13.2 클라이언트 사이드 렌더링(CSR)
CSR은 **SPA**를 구축해 페이지 새로고침 없는 탐색을 지원한다.
클라이언트가 처음 요청 시 전체 UI와 로직을 가져와 API와 상호작용하는 방식이다.

#### 장점
페이지 전환 시 렌더링을 위한 새로운 요청을 보내지 않아 뷰 전환이 빠르다.

#### 단점
**대규모 자바스크립트 번들**로 FCP, TTI가 늘어나고, 크롤러가 콘텐츠를 늦게 받아 **SEO**에 영향을 줄 수 있다. 동적 컨트롤 규모가 클수록 페이지 복잡도와 성능 부담이 커진다.

## 13.3 서버 사이드 렌더링(SSR)
SSR은 **요청마다 HTML을 재생성**하는 방식이며, HTML은 서버에서 생성된다.
SSR은 주로 인증 상태나 개인화 데이터가 필요한 페이지에 적합하다.

#### 장점
**데이터 fetching**이 서버에서 이뤄지므로, 클라이언트로 전송되는 JS 양이 줄어든다.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이거랑 SEO 최적화가 진짜 크죠,,, 😢 애증의 Next.js


#### 단점
**하이드레이션 비용**이 존재하므로, SSR에서는 언제나 이 과정을 최적화해야 한다.


## 13.4 정적 렌더링
정적 렌더링(static rendering)은 **전체 페이지의 HTML을 빌드 시점에 미리 생성**하고, 이후 빌드가 끝날 때까지 내용이 변하지 않는다.
회사 소개, 문의하기, 블로그 글, 전자상거래의 상품 상세처럼 **자주 변경되지 않는 페이지**에 가장 적합하다.

#### 장점
빌드 시점에 생성된 HTML은 CDN이나 엣지 네트워크에 배포되어 빠르게 캐싱·전달될 수 있어 FCP를 단축할 수 있다.


정적 렌더링에는 다음과 같은 변형이 존재한다:

1. **데이터베이스의 동적 데이터를 활용한 리스트 페이지 정적 생성**
리스트 페이지를 서버에서 데이터와 함께 생성한다. Next.js Pages Router라면 getStaticProps(), App Router라면 fetch()의 cache 옵션으로 구현한다.

사용 예시: **리스트·카테고리 페이지**처럼 **같은 데이터 묶음을 모든 방문자에게 똑같이** 보여줄 때

2. **동적 경로를 사용한 상세 페이지 정적 생성**
고정된 템플릿에 동적 데이터를 병합하여 서버에서 경로별로 개별 HTML을 빌드한다. Pages Router는 getStaticPaths(), App Router는 generateStaticParams()를 쓴다.

사용 예시: 상품 페이지나 블로그 페이지처럼 **URL마다 고유 콘텐츠**가 있는 경우

3. **클라이언트 fetch 기반 정적 렌더링**
미리 렌더링된 스켈레톤 UI가 전달되고, 클라이언트가 SWR 라이브러리 등으로 데이터를 가져와 화면을 갱신한다.

사용 예시: SNS 피드 같이 데이터가 빠르게 변하거나, 항상 최신 목록을 표시해야하는 동적인 화면에 유용하다.


### 13.4.1 점진적 정적 생성 (ISR)
ISR은 **정적 렌더링과 SSR을 조합**한 방식이다. 특정 페이지를 미리 렌더링하되, **동적 페이지는 사용자 요청 시 on-demand로 생성**한다.

#### 장점
빌드 시간이 짧아진다.
일정 간격마다 캐시를 무효화해 페이지를 재생성할 수 있다 -> 주기적으로 최신 정보를 제공할 수 있다.


ISR은 아래 두가지 측면에서 작동한다:
##### 새로운 페이지 추가
빌드 후에도 웹사이트에 새로운 페이지를 추가할 수 있다. 새로운 페이지는 첫 요청 시 즉시 생성된다.

사용 예시: 블로그에 새 글이 빌드 이후에 추가돼도, 사용자가 URL을 직접 치면 바로 생성·캐시되길 원하는 경우

##### 기존 페이지 업데이트
타임아웃을 설정해 N초마다 자동 재검증할 수 있다. 재검증 시간 동안 사용자는 이전 버전을 보게 된다.

사용 예시: 특정 컨텐츠에 대한 페이지가 있고, 조회수/좋아요 수가 자주 바뀌지만 초 단위 실시간은 필요 없는 상황. 약 5분 마다 최신 조회수/좋아요 수를 보여주면 되는 경우.

### 13.4.2 On-demand ISR
On-demand ISR은 **정해진 시간 간격 대신 특정 이벤트 발생 시**(CMS 저장, 결제 완료 후 웹훅 등 콘텐츠 변경이 일어 났을 때) 페이지를 재생성한다.

#### 장점
**즉각적인 최신화**
재생성 직후 엣지 네트워크 전체 캐시를 무효화해 전 세계 사용자에게 **항상 최신 페이지**를 제공한다.

**함수 호출 최소화**
이벤트 발생 시 서버리스 함수는 **단 한 번만** 실행해 새 HTML을 원본 스토리지에 저장하고, 이후 요청은 각 엣지 노드가 다운로드 받아 **캐싱**한다.

**운영 비용 절감**
중복 렌더링과 불필요한 함수 호출이 사라져 **클라우드 호출, 컴퓨팅 비용**을 크게 줄인다.

#### 일반 ISR과의 차이점
 - TTL 만료를 기다릴 필요가 없다.
 - 첫 방문자조차 스테일 페이지를 보지 않는다.


### 13.4.3 정적 렌더링 요약
- **순수 정적 렌더링**: 동적 데이터가 없는 페이지에 적합하다.
- **클라이언트 fetch 정적 렌더링**: 매 페이지 로드 시 데이터가 새로고침돼야 하는 목록형 페이지에 적합하다.
- **ISR**: 일정 간격으로 재생성이 필요한 페이지에 적합하다.
- **On-demand ISR**: 이벤트 기반으로 즉시 재생성이 필요한 페이지에 적합하다.

단, 사용자마다 내용이 크게 달라지는 개인 맞춤형 페이지에는 **SSR**이 더 효율적이다.

## 13.5 스트리밍 SSR
스트리밍 SSR은 **서버가 HTML을 작은 청크 단위로 전송**해 FCP와 TTI를 단축한다.
Node.js 스트림 기능을 사용하며, React에서는 renderToNodeStream() 혹은 renderToStaticNodeStream() API를 제공한다.

클라이언트는 데이터를 받는 즉시 UI를 그리기 시작하고, 모든 청크를 받은 뒤 hydrate()를 호출해 이벤트 핸들러를 연결한다.

#### 장점
네트워크 정체 시 청크 전송을 일시 중단할 수 있어 서버 메모리·I/O 부담이 적다.
결과적으로 **초기 로딩 경험이 빨라지고, 트래픽 급증에도 응답성을 유지**할 수 있다.


## 13.6 엣지 SSR
엣지 SSR(edge SSR)은 **CDN의 엣지 노드에서 서버 렌더링을 수행**해 **콜드 부트 시간을 최소**화한다.

#### 장점
서버리스 함수가 페이지를 생성하고, 생성된 문서를 스트리밍으로 전달해 각 컴포넌트를 빠르게 하이드레이션한다.

예를 들어 지역 특화 리스트 페이지에서 정적 부분은 빌드 시점에, 리스트 부분은 엣지 노드에서 서버 렌더링하도록 분리해 **정적 성능과 SSR 동적 이점을 동시에** 확보할 수 있다.

> 콜드 부트:
> 사용자 요청이 처음 도착했을 때 발생하는 초기 응답 지연을 의미
>
> 엣지:
> “사용자와 네트워크상 가장 가까운, 경량 서버리스 환경을 갖춘 CDN 노드”를 가리키는 집합적 용어
>
> 서버리스:
> 서버 관리(프로비저닝·패치·스케일링)를 클라우드 공급자가 완전히 맡고, 개발자는 짧은 함수 단위 코드만 올려 두면 자동으로 실행·확장되는 실행 모델

## 13.7 하이브리드 렌더링
하이브리드 렌더링은 **여러 렌더링 전략을 조합**해 상황별 최적의 결과를 제공하는 접근 방식이다. 정적으로 제공할 수 있는 페이지는 미리 렌더링하고, 애플리케이션 핵심 페이지는 ISR·SSR·CSR·스트리밍 등 동적 전략을 선택하여 동작시킨다.

#### 장점
- 페이지 별 최적화가 가능하며 확장성이 높다.
- FCP와 TTI를 단축시킬 수 있다.
- 서버 비용을 효율적으로 관리할 수 있다.
- 페이지 새로고침 없이 탐색이 가능하다.


## 13.8 점진적 하이드레이션
점진적 하이드레이션은 각 노드를 시간/우선순위에 따라 개별적으로 하이드레이션하여 필요한 최소한의 자바스크립트만 요청하는 방식이다.

#### 장점
초기 페이로드가 작아 **FCP·TTI가 단축**된다.
서버 렌더링 DOM 트리가 파괴되는 문제를 예방하며, 노드별 하이드레이션 비용을 줄인다.

**요구 사항**
- 모든 컴포넌트를 SSR로 렌더링할 수 있어야 한다.
- 조각 단위 코드 스플리팅을 지원해야 한다.
- 개발자가 정의한 순서대로 클라이언트 사이드에서 조각 별 하이드레이션을 지원해야 한다.
- 이미 하이드레이션된 조각의 입력 상태가 유지돼야 한다.
- 지연된 조각에는 **로딩 중 표시**(spinner 등)가 가능해야 한다.

React **동시성 모드(concurrent mode)** 도입 시 요구사항 충족이 쉬워진다:
- 사용자 입력 같은 높은 우선순위 작업이 필요하면 하이드레이션을 일시 중지하고 해당 작업으로 전환
- lazy() + Suspense를 사용해 지연로드 및 로딩중 표시가 가능
- SuspenseList()로 우선순위를 제어

## 13.9 아일랜드 아키텍처
아일랜드 아키텍처는 **정적 HTML 위에 독립적인 상호작용 영역(아일랜드)을 올려 자바스크립트 전송량을 최소화하는 컴포넌트 기반 패러다임**이다. 페이지의 대부분은 순수 정적 콘텐츠로 이루어지며, 상호작용이 필요한 부분만 자바스크립트가 결합된 아일랜드로 동작한다.

아일랜드 내부 상태는 해당 컴포넌트 범위에만 국한되며, 특정 아일랜드의 성능 문제나 오류가 다른 아일랜드에 영향을 주지 않는다.

👉 위젯처럼 별도의 독립적인 애플리케이션처럼 동작

### 점진적 하이드레이션과의 차이점
- **점진적 하이드레이션:** 페이지가 개별 컴포넌트의 스케줄링 및 하이드레이션을 제어하는 Top-Down 구조
- **아일렌드 아키텍처:** 각 아일랜드 컴포넌트가 자체적으로 하이드레이션 스크립트를 가지며 **페이지 상단 트리의 통제 없이** 스스로 하이드레이션하는 Bottom-Up 구조
Comment on lines +205 to +207
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍



### 아일랜드 아키텍처 구현하기
서버와 클라이언트 모두에서 동일 코드로 렌더링하는 **동형 렌더링(isomorphic rendering)** 을 지원한다.

아일랜드 아키텍처를 지원하는 프레임워크:
- **Marko**: 스트리밍 렌더링 + 자동 부분 하이드레이션을 지원한다.
- **Astro**: React·Svelte·Vue 등 UI 컴포넌트를 불러와 정적 페이지를 생성하며 **기본적으로 부분 하이드레이션**을 제공한다.
- **Eleventy + Preact**: Eleventy 정적 사이트에 Preact 컴포넌트를 함께 사용해 부분 하이드레이션을 구현한다.

#### 장점
- **성능**: 필요한 코드량만 전송하므로 로드 속도가 빨라진다.
- **SEO**: 모든 정적 콘텐츠가 서버에서 렌더링되어 SEO에 유리하다.
- **콘텐츠 우선순위**: 핵심 콘텐츠를 즉시 노출한다.
- **접근성**과 **컴포넌트 기반 유지보수성**이 향상된다.

#### 단점
- 아직 초기 단계이며, Astro·Marko 등 특정 프레임워크 의존도가 높다.
- 대규모 소셜 미디어처럼 상호작용이 위주가 되어 **수천 개 아일랜드**가 필요한 페이지에는 적합하지 않다.


## 13.10 리액트 서버 컴포넌트(RSC)
리액트 서버 컴포넌트는 **React 애플리케이션의 일부를 서버에서 렌더링**하고, 그 결과만 클라이언트로 전달하는 기능이다.

#### 장점
번들 크기를 ‘0’으로 줄이고, 서버-컴포넌트와 클라이언트-컴포넌트 사이를 매끄럽게 연결(니팅 knitting)하여 **클라이언트 JS 전송량을 크게 줄일 수 있다.**


> 니팅:
> 서버 컴포넌트 트리와 클라이언트 컴포넌트 트리를 한 화면에서 엮어 내보내는 과정이다.


### RSC VS SSR

| **구분** | **서버 컴포넌트(RSC)** | **기존 SSR** |
| ------------- | -------------------------------------------------------------- | -------------------------------------------------------------------------------- |
| **클라이언트 전송** | **JS 번들이 전달되지 않는다.** 따라서 브라우저로 가는 코드 용량이 0이다 → 초기 로딩·UX가 개선된다. | HTML과 함께 **JS 번들**이 반드시 전송된다. |
| **데이터 접근 위치** | **컴포넌트 어느 깊이에서도** DB·API 호출이 가능하다. (컴포넌트 내부 async/await) | Next.js 기준으로 **페이지 최상위 함수**getInitialProps / getServerSideProps에서만 데이터 접근이 가능하다. |
| **리렌더링 방식** | **클라이언트 상태를 유지**한 채 서버에서 필요한 트리만 다시 렌더링할 수 있다. | HTML 전체를 다시 생성해 보내야 데이터가 갱신된다. 클라이언트 상태는 새로 하이드레이션해야 한다. |


## 마무리

![[Pasted image 20250616004412.png]]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오 이미지까지 좋습니당 👍

![[Pasted image 20250616004524.png]]
Comment on lines +251 to +252
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이미지 안보여용

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

뜨헣

> 애플리케이션 유형·페이지 특성·업데이트 빈도에 따라 **패턴을 선택하거나 조합**해야 한다.
Loading