Astro 와 Cloudflare Pages 로 개인 사이트 만들기
이 사이트를 만들면서 내린 선택들을 정리해 둡니다. 나중에 구조를 바꿀 때 “왜 이렇게 했더라”를 다시 추적하지 않으려는 목적이 큽니다.
왜 Astro 인가
블로그는 대부분 읽기 전용입니다. 서버에서 매 요청마다 HTML 을 만들 이유가 없고, 클라이언트에 프레임워크 런타임을 내려보낼 이유는 더 없습니다. Astro 는 기본이 정적 HTML 이고, 인터랙션이 필요한 컴포넌트만 선택적으로 하이드레이션합니다.
콘텐츠 컬렉션도 결정적이었습니다. 프론트매터에 스키마를 붙일 수 있어서, 오타나 필드 누락이 런타임이 아니라 빌드 타임에 잡힙니다.
const blog = defineCollection({
loader: glob({ pattern: '**/*.{md,mdx}', base: './src/content/blog' }),
schema: z.object({
title: z.string(),
description: z.string(),
pubDate: z.coerce.date(),
tags: z.array(z.string()).default([]),
draft: z.boolean().default(false),
}),
});
pubDate 를 빼먹으면 배포가 아니라 빌드가 실패합니다. 이게 훨씬 낫습니다.
왜 Workers 가 아니라 Pages 인가
Cloudflare 는 신규 프로젝트에 Workers 를 권장하지만, 이 사이트에는 Pages 를 골랐습니다.
| Pages | Workers | |
|---|---|---|
| 기본 URL | <프로젝트>.pages.dev |
<이름>.<계정>.workers.dev |
| 404 처리 | 404.html 자동 |
설정 필요 |
| Cron·Durable Objects | 없음 | 있음 |
| 신규 기능 투자 | 중단 | 진행 중 |
Workers 전용 기능을 하나도 쓰지 않는 100% 정적 사이트라서 실질적인 손해가 없었고, URL 이 한
단계 짧다는 점이 남았습니다. 나중에 서버 로직이 필요해지면 wrangler.jsonc 를 추가해 Workers 로
옮기면 됩니다. 빌드 산출물(dist/)은 양쪽이 동일합니다.
한국어 타이포그래피
한 가지는 꼭 짚고 가야 합니다. 기본 설정으로 두면 한국어 문장이 어절 중간에서 끊깁니다.
body {
word-break: keep-all;
overflow-wrap: break-word;
}
keep-all 이 어절 단위로 줄을 바꾸고, overflow-wrap 이 긴 URL 처럼 한 덩어리가 화면을 넘칠 때만
예외적으로 끊어줍니다. 두 줄이지만 읽는 느낌이 확 달라집니다.
폰트는 Pretendard 를 동적 서브셋으로 self-host 했습니다. 92개 파일로 쪼개져 있고 각각
unicode-range 가 붙어 있어서, 브라우저가 실제로 쓰는 글자 범위만 내려받습니다.
배포
GitHub 저장소를 Pages 프로젝트에 연결해두면 main 에 푸시할 때마다 자동으로 빌드·배포되고,
다른 브랜치에는 프리뷰 URL 이 생깁니다. 빌드 설정은 두 줄이면 끝입니다.
Build command: npm run build
Build output directory: dist
로컬에서 배포 결과를 미리 확인하려면 npm run preview 대신 아래를 씁니다. 404 처리처럼
Pages 런타임에서만 재현되는 동작이 있기 때문입니다.
npm run build
npx wrangler pages dev ./dist