증분 정적 재생성 (ISR)
ISR(Incremental Static Regeneration)은 SSG의 장점은 유지하면서 단점을 보완해요. 핵심 아이디어는:
1.
처음 요청 시 렌더링하고 캐시에 저장
2.
이후 요청은 캐시된 HTML 반환 (빠름)
3.
일정 시간이 지나면 백그라운드에서 재생성
직접 구현해보기
// server.ts
import { Hono } from "hono";
import { renderToString } from "react-dom/server";
import BlogPost from "./pages/BlogPost";
const app = new Hono();
// 캐시 저장소
const cache = new Map<string, { html: string; timestamp: number }>();
const REVALIDATE_SECONDS = 60; // 60초마다 재검증
app.get("/blog/:id", async (c) => {
const id = c.req.param("id");
const cacheKey = `/blog/${id}`;
const now = Date.now();
// 1. 캐시 확인
const cached = cache.get(cacheKey);
if (cached) {
const age = (now - cached.timestamp) / 1000;
if (age < REVALIDATE_SECONDS) {
// 캐시가 신선함 → 그대로 반환
return c.html(cached.html);
}
// 캐시가 오래됨 → 일단 반환하고, 백그라운드에서 재생성
regenerateInBackground(cacheKey, id);
return c.html(cached.html);
}
// 2. 캐시 없음 → 새로 렌더링
const html = await renderPage(id);
cache.set(cacheKey, { html, timestamp: now });
return c.html(html);
});
async function renderPage(id: string) {
const post = await fetchPost(id);
const content = renderToString(<BlogPost post={post} />);
return `
<!DOCTYPE html>
<html>
<body>
<div id="root">${content}</div>
<script>
window.__INITIAL_DATA__ = ${JSON.stringify(post)};
</script>
<script type="module" src="/client.tsx"></script>
</body>
</html>
`;
}
function regenerateInBackground(cacheKey: string, id: string) {
// 백그라운드에서 재생성 (요청을 블로킹하지 않음)
setImmediate(async () => {
const html = await renderPage(id);
cache.set(cacheKey, { html, timestamp: Date.now() });
console.log(`[ISR] ${cacheKey} 재생성 완료`);
});
}
TypeScript
복사
ISR의 동작 흐름
[첫 번째 요청] /blog/hello
→ 캐시 없음 → 렌더링 → 캐시 저장 → 응답
[두 번째 요청] (30초 후)
→ 캐시 있음 (30초 < 60초) → 캐시된 HTML 응답
[세 번째 요청] (70초 후)
→ 캐시 있음 (70초 > 60초, stale)
→ 캐시된 HTML 응답 (사용자는 기다리지 않음)
→ 백그라운드에서 재생성 시작
[네 번째 요청] (71초 후)
→ 새로 생성된 캐시 응답
Plain Text
복사
stale-while-revalidate 패턴이에요. 오래된 캐시라도 일단 빠르게 응답하고, 백그라운드에서 갱신해요.
SSR vs SSG vs ISR
방식 | 렌더링 시점 | 장점 | 단점 |
SSR | 매 요청 | 항상 최신 데이터 | 서버 부하 |
SSG | 빌드 시 | 가장 빠름 | 업데이트 어려움 |
ISR | 첫 요청 + 주기적 | 빠름 + 업데이트 | 구현 복잡 |
어떤 방식이 좋은지는 페이지 특성에 따라 달라요:
•
실시간 데이터 (주식, 채팅) → SSR
•
거의 안 바뀌는 콘텐츠 (문서, 블로그) → SSG
•
가끔 바뀌는 콘텐츠 (상품 목록, 뉴스) → ISR
