6.2 KiB
6.2 KiB
프로젝트 구조 및 설명
dd/
├── src/
│ ├── lib/
│ │ └── counter-do.ts # Durable Object 구현체
│ ├── routes/
│ │ ├── api/counter/
│ │ │ └── +server.ts # WebSocket 엔드포인트 (API Route)
│ │ ├── +layout.svelte # 전역 레이아웃
│ │ └── +page.svelte # 메인 페이지 (실시간 카운터 UI)
│ ├── app.d.ts # TypeScript 전역 타입 정의
│ ├── app.css # Tailwind CSS 글로벌 스타일
│ ├── app.html # HTML 템플릿
│ └── hooks.server.ts # SvelteKit 서버 훅 (Durable Object export)
├── static/
│ └── robots.txt # SEO용 robots.txt
├── .svelte-kit/ # SvelteKit 빌드 출력
│ ├── cloudflare/
│ │ ├── _worker.js # 생성된 Worker 파일
│ │ └── _app/ # 클라이언트 자산
│ └── output/
│ ├── client/ # 클라이언트 빌드
│ └── server/ # 서버 빌드
├── wrangler.jsonc # Cloudflare Workers 설정
├── svelte.config.js # SvelteKit 설정
├── vite.config.ts # Vite 설정
├── tailwind.config.ts # Tailwind CSS 설정
├── tsconfig.json # TypeScript 설정
├── package.json # 프로젝트 의존성
├── README.md # 프로젝트 문서
├── QUICKSTART.md # 빠른 시작 가이드
└── DEPLOYMENT.md # 배포 가이드
주요 파일 설명
1. src/lib/counter-do.ts - Durable Object
Cloudflare Durable Objects 클래스로, 다음을 담당합니다:
- WebSocket 연결 관리
- 카운터 상태 저장 및 업데이트
- 모든 클라이언트에 상태 브로드캐스트
- 영구 저장소(Durable Objects Storage)에 데이터 저장
export class CounterDurableObject {
// WebSocket 세션 관리
// 카운트 상태 관리
// fetch() - WebSocket 업그레이드 처리
// webSocketMessage() - 클라이언트 메시지 처리
// webSocketClose() - 연결 종료 처리
// broadcast() - 모든 클라이언트에 상태 전송
}
2. src/routes/api/counter/+server.ts - API 라우트
SvelteKit API 엔드포인트로 WebSocket 연결 요청을 Durable Object로 전달합니다:
export const GET: RequestHandler = async ({ request, platform }) => {
const id = platform?.env.COUNTER.idFromName('global-counter');
const stub = platform.env.COUNTER.get(id);
return stub.fetch(request);
};
3. src/routes/+page.svelte - 클라이언트 UI
실시간 카운터 UI를 렌더링하고 WebSocket을 통해 서버와 통신합니다:
<script lang="ts">
let count = $state(0);
let online = $state(0);
let ws = $state<WebSocket | null>(null);
function connectWebSocket() { /* ... */ }
function incrementCount() { /* ... */ }
function resetCount() { /* ... */ }
</script>
4. src/hooks.server.ts - 서버 훅
Durable Object을 Worker에서 사용할 수 있도록 export합니다:
export { CounterDurableObject } from '$lib/counter-do';
5. wrangler.jsonc - Cloudflare 설정
Worker 및 Durable Objects 바인딩을 설정합니다:
{
"durable_objects": {
"bindings": [{
"name": "COUNTER",
"class_name": "CounterDurableObject"
}]
},
"migrations": [...]
}
데이터 흐름
WebSocket 연결 흐름
클라이언트 브라우저
↓ (WebSocket 연결 요청)
/api/counter (+server.ts)
↓ (Durable Object ID 생성)
Durable Object Stub
↓ (fetch() 호출)
CounterDurableObject
↓ (WebSocket 페어 생성)
클라이언트 ← → 서버 (양방향 통신)
카운트 증가 흐름
클라이언트: 버튼 클릭
↓ (WebSocket 메시지)
Durable Object: webSocketMessage()
↓ (카운트 증가)
Durable Object Storage: 저장
↓ (broadcast())
모든 연결된 클라이언트: 실시간 업데이트
기술 스택
프론트엔드
- Svelte 5: 최신 Svelte 5의 Runes API 사용
- Tailwind CSS 4: 유틸리티 우선 CSS 프레임워크
- TypeScript: 타입 안전성
백엔드
- SvelteKit: 풀스택 웹 프레임워크
- Cloudflare Workers: 서버리스 엣지 컴퓨팅
- Durable Objects: 상태 저장 및 협업
- WebSocket Hibernation API: 저비용 실시간 통신
빌드 & 배포
- Vite: 빠른 빌드 도구
- Wrangler: Cloudflare Workers CLI
- @sveltejs/adapter-cloudflare: SvelteKit → Cloudflare 어댑터
개발 워크플로우
로컬 개발
pnpm dev # Vite 개발 서버
pnpm build # 프로덕션 빌드
pnpm cf:dev # Wrangler 로컬 서버
배포
pnpm deploy # Cloudflare에 배포
pnpm cf:tail # 실시간 로그
테스트
pnpm check # TypeScript 및 Svelte 체크
pnpm format # Prettier 포맷팅
pnpm lint # 린팅 체크
환경 변수
현재 프로젝트는 환경 변수를 사용하지 않습니다. 모든 설정은 wrangler.jsonc에 있습니다.
필요한 경우 .env 파일을 추가하고 다음과 같이 사용할 수 있습니다:
# .env
VITE_API_URL=https://your-api.com
// 사용
import { env } from '$env/dynamic/public';
console.log(env.VITE_API_URL);
확장 아이디어
-
여러 카운터 룸
- URL 파라미터로 룸 ID 전달
- 각 룸마다 독립적인 Durable Object 인스턴스
-
사용자 인증
- Cloudflare Access 통합
- 사용자별 권한 관리
-
영속적 히스토리
- SQLite (D1) 통합
- 카운트 변경 로그
-
실시간 채팅
- WebSocket을 활용한 채팅 기능
- 메시지 브로드캐스팅
-
분석 및 모니터링
- Cloudflare Analytics 통합
- 커스텀 메트릭 수집