프론트엔드 스터디 대면 9주차: Next.js 렌더링 진화와 웹.
Next.js가 무엇이고 왜 필요한지 React와 비교해 이해한 뒤, CSR부터 SSR, SSG, ISR, PPR까지 렌더링 전략과 Web Vitals를 정리하며 스터디를 마무리합니다.
---
| 구분 | React | Next.js |
|---|---|---|
| 핵심 역할 | UI를 컴포넌트로 만들기 | React 앱을 서비스 구조로 만들기 |
| 라우팅 | 별도 라이브러리 필요 | 파일/폴더 기반 라우팅 제공 |
| 렌더링 | 주로 브라우저에서 JS로 그림 | CSR/SSR/SSG/ISR 등 선택 가능 |
| 데이터 처리 | 클라이언트 fetch 중심으로 시작 | 서버 컴포넌트, 캐싱, revalidate 등 제공 |
| 배포/인프라 | 직접 결정할 부분이 많음 | Vercel/Edge/서버리스 흐름과 잘 맞음 |
이 화면은 검색엔진이 읽어야 하나요? 데이터는 자주 바뀌나요, 거의 고정되어 있나요? 사용자가 처음 봐야 하는 핵심 콘텐츠는 무엇인가요? 클릭, 입력, 상태 변화가 필요한 영역은 어디인가요? 이 코드는 브라우저에서 실행되어야 하나요, 서버에서 실행되어야 하나요?
서버 → 빈 HTML 전송 → JS 다운로드 → JS 실행 → DOM 생성 → 화면 표시<!-- 서버가 보내는 HTML (실제로 이게 전부) -->
<html>
<body>
<div id="root"></div>
<script src="/bundle.js"></script>
</body>
</html><strong>장점</strong>: 첫 로딩 후 페이지 이동이 빠르고, 서버 부하가 적음 <strong>단점</strong>: 첫 화면이 늦게 뜸, 검색 엔진이 내용을 읽기 어려움(SEO)
---
서버에서 HTML 완성 → 완성된 HTML 전송 → 화면 즉시 표시 → JS 다운로드 → Hydration| 지표 | CSR | SSR |
|---|---|---|
| FCP (첫 콘텐츠가 보이는 시점) | 느림 (JS 실행 후) | 빠름 (HTML 도착 즉시) |
| SEO | 불리 (빈 HTML) | 유리 (완성된 HTML) |
| 서버 부하 | 없음 | 매 요청마다 생성 |
---
정적 HTML (보이지만 클릭해도 반응 없음)
↓ JS 다운로드 + Hydration
동적 HTML (클릭, 입력 등 가능)---
CSR → SSR → SSG → ISR → Streaming SSR → PPR[SSR] 요청 → 서버가 HTML 생성 → 전송 (매번)
[SSG] 빌드 → HTML 생성 → CDN에 올림 → 요청 → 바로 전송 (빠름)<strong>장점</strong>: 가장 빠름, 서버 부하 없음 <strong>단점</strong>: 데이터가 바뀌면 전체를 다시 빌드해야 함
// Next.js에서 ISR 설정
export const revalidate = 60; // 60초마다 재생성0~60초: 캐시 그대로 반환 (SSG처럼 빠름)
60초 후: 요청이 오면 기존 캐시 반환 + 백그라운드에서 새 HTML 생성
→ 다음 요청부터 새 HTML 서빙<Layout>
<Header /> {/* 즉시 전송 */}
<Suspense fallback={<CommentSkeleton />}>
<Comments /> {/* DB 조회 끝나면 전송, 그 전엔 Skeleton 표시 */}
</Suspense>
</Layout>export default function ProductPage() {
return (
<div>
{/* 정적: 빌드 시 생성, CDN에서 즉시 전송 */}
<ProductName />
<ProductImage />
{/* 동적: 요청 시 서버에서 생성, 준비되면 Streaming */}
<Suspense fallback={<PriceSkeleton />}>
<Price />
</Suspense>
</div>
);
}| | 속도 | 데이터 신선함 | 어울리는 콘텐츠 | | :-- | :--------- | :------------- | :----------------------------- | | SSG | 가장 빠름 | 빌드 시점 고정 | 블로그, 문서, 변경 없는 페이지 | | SSR | 느림 | 항상 최신 | 로그인 필요, 실시간 데이터 | | ISR | SSG와 동일 | 약간의 지연 | 블로그, 상품 목록 | | PPR | SSG급 | 컴포넌트별 | 상품 상세, 대시보드 |
---
// Server Component (기본값)
// 서버에서만 실행됨. 브라우저로 JS가 안 감.
async function PostList() {
const posts = await db.query("SELECT * FROM posts");
return (
<ul>
{posts.map((p) => (
<li key={p.id}>{p.title}</li>
))}
</ul>
);
}
// Client Component ('use client' 선언 필요)
// 브라우저에서 실행됨. onClick, useState 사용 가능.
("use client");
function LikeButton() {
const [liked, setLiked] = useState(false);
return <button onClick={() => setLiked(true)}>좋아요</button>;
}| 구분 | Server Component | Client Component |
|---|---|---|
| 실행 위치 | 서버 | 브라우저 |
| useState, onClick | ❌ 불가 | ✅ 가능 |
| DB 직접 접근 | ✅ 가능 | ❌ 불가 |
| JS 번들 포함 | ❌ 포함 안 됨 | ✅ 포함됨 |
---
페이지 요청
│ 0.5s 헤더, 네비게이션 표시
│ 1.2s 메인 이미지 표시 ← 이게 LCP
│ 1.8s 나머지 콘텐츠
좋음: ≤ 2.5s / 개선 필요: 2.5~4s / 나쁨: > 4sSSG나 SSR은 LCP를 빠르게 만들고, CSR은 느리게 만드는 주요 원인입니다.
사용자가 버튼 클릭
│ JS 이벤트 핸들러 실행
│ 상태 업데이트
│ DOM 변경 + 화면 다시 그림 ← 여기까지가 INP
좋음: ≤ 200ms / 나쁨: > 500msHydration이 무거우면 JS 메인 스레드가 막혀서 INP가 나빠집니다. Server Component를 늘리면 Hydration 대상이 줄어 INP가 개선됩니다.
좋음: ≤ 0.1 / 나쁨: > 0.25흔한 원인: 이미지 크기 미지정, 폰트 로딩 후 텍스트 크기 변화
해결: width/height 명시, Skeleton으로 공간 미리 확보
| 지표 | 측정하는 것 | 좋음 기준 | 주요 영향 요소 |
|---|---|---|---|
| LCP | 콘텐츠 표시 속도 | ≤ 2.5s | 렌더링 방식(SSG/SSR vs CSR), 이미지 크기 |
| INP | 인터랙션 반응 속도 | ≤ 200ms | JS 번들 크기, Hydration 무게 |
| CLS | 레이아웃 안정성 | ≤ 0.1 | 이미지 크기, Skeleton, 폰트 |
---
<strong>Mode: Navigation</strong> — 페이지 첫 로딩 시 측정 (가장 일반적) <strong>Device: Mobile</strong>로 체크하면 더 엄격하게 측정됨
HTML 응답에 <strong>내용이 가득</strong> → SSR 또는 SSG HTML 응답에 <strong>빈 div만</strong> → CSR
크롬에서 아무 사이트나 열고 DevTools → Lighthouse 실행 LCP / INP / CLS 점수 확인 "Opportunities" 섹션에서 개선 제안 읽기 Network 탭으로 첫 HTML 응답 확인 — 내용이 있는지 없는지
---
데이터가 거의 안 바뀐다 → <strong>SSG</strong> 실시간 데이터가 필요하다 → <strong>SSR</strong> 가끔 바뀌는 데이터 → <strong>ISR</strong> 페이지 일부만 실시간 → <strong>PPR + Streaming</strong> 클릭·입력이 필요한 컴포넌트만 → <strong>Client Component</strong>
렌더링 방식을 잘 선택하는 것 자체가 프론트엔드 성능 최적화의 절반입니다.
---
이 페이지는 검색엔진이 읽어야 하는가? → SSR/SSG/ISR 고려 데이터는 얼마나 자주 바뀌는가? → SSG/ISR/SSR 선택 클릭과 입력이 필요한 부분은 어디인가? → Client Component 범위 최소화 첫 화면에서 가장 큰 콘텐츠는 무엇인가? → LCP 기준으로 이미지/HTML 확인 화면은 떴는데 클릭이 늦지 않은가? → Hydration과 JS 번들 크기 확인
---
이번 주 학습 자료(week9)
vinext는 왜 빠를까? — SSR, Vite, Edge, Web Vitals까지 (참고)
Post Q&A
프론트엔드 스터디 대면 9주차: Next.js 렌더링 진화와 웹 퍼포먼스 전체를 기준으로 질문과 피드백을 받아요.답을 본 뒤에는 이 내용을 댓글로 달아서 서징에게도 물어볼 수 있어요. 작성자가 직접 볼 수 있어요!
비동기와 async/await를 배운 뒤, 대면에서는 API를 단순 호출 방법이 아니라 프론트엔드와 백엔드 사이의 계약으로 바라봅니다. HTTP, REST, CORS, 프록시, API 클라이언트 구조, TanStack Query와 파일 배치까지 연결합니다.