정적 생성 (SSG)
지금까지 구현한 SSR은 요청이 올 때마다 렌더링해요. 하지만 블로그 글처럼 내용이 자주 바뀌지 않는 페이지는 어떨까요?
요청 1: /blog/hello → renderToString() → HTML
요청 2: /blog/hello → renderToString() → HTML ← 같은 결과
요청 3: /blog/hello → renderToString() → HTML ← 계속 반복
Plain Text
복사
매번 똑같은 결과를 만드는 건 낭비예요.
아이디어: 미리 렌더링해두기
정적 생성(Static Site Generation, SSG)의 핵심은 간단해요. 빌드 시점에 HTML을 미리 만들어서 파일로 저장해두는 거예요.
// build.ts - 빌드 스크립트
import { renderToString } from "react-dom/server";
import fs from "fs";
import BlogPost from "./pages/BlogPost";
// 빌드할 페이지 목록
const posts = [
{ id: "hello", title: "Hello World", content: "첫 번째 글입니다." },
{ id: "ssr", title: "SSR 이해하기", content: "SSR은..." },
];
// 각 페이지를 미리 렌더링
for (const post of posts) {
const html = renderToString(<BlogPost post={post} />);
const fullHtml = `
<!DOCTYPE html>
<html>
<body>
<div id="root">${html}</div>
<script>
window.__INITIAL_DATA__ = ${JSON.stringify(post)};
</script>
<script type="module" src="/client.tsx"></script>
</body>
</html>
`;
// 파일로 저장
fs.writeFileSync(`./dist/blog/${post.id}.html`, fullHtml);
}
console.log(`${posts.length}개의 페이지가 생성되었습니다.`);
TypeScript
복사
이 스크립트를 빌드 시점에 실행하면:
dist/
blog/
hello.html ← 미리 렌더링된 HTML
ssr.html ← 미리 렌더링된 HTML
Plain Text
복사
정적 파일 서빙
이제 서버는 렌더링할 필요 없이 파일만 보내면 돼요.
// server.ts
import { Hono } from "hono";
import { serveStatic } from "hono/serve-static";
const app = new Hono();
// 정적 파일 서빙
app.use("/blog/*", serveStatic({ root: "./dist" }));
export default app;
TypeScript
복사
요청: /blog/hello
서버: dist/blog/hello.html 파일을 그대로 전송
Plain Text
복사
렌더링 비용이 0이에요. CDN에 올려두면 전 세계 어디서든 빠르게 응답할 수 있죠.
SSG의 한계
하지만 SSG에는 한계가 있어요.
1.
빌드 시점에 모든 페이지를 알아야 한다: 동적으로 생성되는 페이지는 처리하기 어려워요.
2.
내용이 바뀌면 다시 빌드해야 한다: 글 하나 수정해도 전체 빌드가 필요해요.
3.
빌드 시간이 길어질 수 있다: 페이지가 수천 개라면?
이 한계를 해결하는 방법이 ISR이에요.
