@kood/claude-code 0.1.2 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/dist/index.js +129 -5
  2. package/package.json +2 -2
  3. package/templates/hono/CLAUDE.md +20 -2
  4. package/templates/hono/docs/architecture/architecture.md +909 -0
  5. package/templates/hono/docs/commands/git.md +275 -0
  6. package/templates/hono/docs/deployment/cloudflare.md +527 -190
  7. package/templates/hono/docs/deployment/docker.md +514 -0
  8. package/templates/hono/docs/deployment/index.md +179 -214
  9. package/templates/hono/docs/deployment/railway.md +416 -0
  10. package/templates/hono/docs/deployment/vercel.md +567 -0
  11. package/templates/hono/docs/library/ai-sdk/index.md +427 -0
  12. package/templates/hono/docs/library/ai-sdk/openrouter.md +479 -0
  13. package/templates/hono/docs/library/ai-sdk/providers.md +468 -0
  14. package/templates/hono/docs/library/ai-sdk/streaming.md +447 -0
  15. package/templates/hono/docs/library/ai-sdk/structured-output.md +493 -0
  16. package/templates/hono/docs/library/ai-sdk/tools.md +513 -0
  17. package/templates/hono/docs/library/hono/env-setup.md +458 -0
  18. package/templates/hono/docs/library/hono/index.md +1 -3
  19. package/templates/hono/docs/library/pino/index.md +437 -0
  20. package/templates/hono/docs/library/prisma/cloudflare-d1.md +503 -0
  21. package/templates/hono/docs/library/prisma/config.md +362 -0
  22. package/templates/hono/docs/library/prisma/index.md +86 -13
  23. package/templates/hono/docs/skills/gemini-review/SKILL.md +116 -116
  24. package/templates/hono/docs/skills/gemini-review/references/checklists.md +125 -125
  25. package/templates/hono/docs/skills/gemini-review/references/prompt-templates.md +191 -191
  26. package/templates/npx/CLAUDE.md +309 -0
  27. package/templates/npx/docs/commands/git.md +275 -0
  28. package/templates/npx/docs/library/commander/index.md +164 -0
  29. package/templates/npx/docs/library/fs-extra/index.md +171 -0
  30. package/templates/npx/docs/library/prompts/index.md +253 -0
  31. package/templates/npx/docs/mcp/index.md +60 -0
  32. package/templates/npx/docs/skills/gemini-review/SKILL.md +220 -0
  33. package/templates/npx/docs/skills/gemini-review/references/checklists.md +134 -0
  34. package/templates/npx/docs/skills/gemini-review/references/prompt-templates.md +301 -0
  35. package/templates/tanstack-start/CLAUDE.md +43 -5
  36. package/templates/tanstack-start/docs/architecture/architecture.md +134 -4
  37. package/templates/tanstack-start/docs/commands/git.md +275 -0
  38. package/templates/tanstack-start/docs/deployment/cloudflare.md +223 -50
  39. package/templates/tanstack-start/docs/deployment/index.md +320 -30
  40. package/templates/tanstack-start/docs/deployment/nitro.md +195 -14
  41. package/templates/tanstack-start/docs/deployment/railway.md +302 -150
  42. package/templates/tanstack-start/docs/deployment/vercel.md +345 -75
  43. package/templates/tanstack-start/docs/guides/best-practices.md +203 -1
  44. package/templates/tanstack-start/docs/guides/env-setup.md +450 -0
  45. package/templates/tanstack-start/docs/library/ai-sdk/hooks.md +472 -0
  46. package/templates/tanstack-start/docs/library/ai-sdk/index.md +264 -0
  47. package/templates/tanstack-start/docs/library/ai-sdk/openrouter.md +371 -0
  48. package/templates/tanstack-start/docs/library/ai-sdk/providers.md +403 -0
  49. package/templates/tanstack-start/docs/library/ai-sdk/streaming.md +320 -0
  50. package/templates/tanstack-start/docs/library/ai-sdk/structured-output.md +454 -0
  51. package/templates/tanstack-start/docs/library/ai-sdk/tools.md +473 -0
  52. package/templates/tanstack-start/docs/library/pino/index.md +320 -0
  53. package/templates/tanstack-start/docs/library/prisma/cloudflare-d1.md +404 -0
  54. package/templates/tanstack-start/docs/library/prisma/config.md +377 -0
  55. package/templates/tanstack-start/docs/library/prisma/index.md +3 -5
  56. package/templates/tanstack-start/docs/library/prisma/schema.md +123 -25
  57. package/templates/tanstack-start/docs/library/prisma/setup.md +0 -7
  58. package/templates/tanstack-start/docs/library/tanstack-start/server-functions.md +80 -2
  59. package/templates/tanstack-start/docs/skills/gemini-review/SKILL.md +116 -116
  60. package/templates/tanstack-start/docs/skills/gemini-review/references/checklists.md +138 -144
  61. package/templates/tanstack-start/docs/skills/gemini-review/references/prompt-templates.md +186 -187
  62. package/templates/hono/docs/git/index.md +0 -180
  63. package/templates/tanstack-start/docs/git/index.md +0 -203
@@ -1,328 +1,665 @@
1
- # Cloudflare Workers 배포
1
+ # Nitro v3 - Cloudflare 배포
2
2
 
3
- > Hono + Cloudflare Workers 상세 가이드
3
+ > **상위 문서**: [배포 가이드](./index.md)
4
+
5
+ Cloudflare Workers/Pages를 사용하여 Hono + Nitro 애플리케이션을 Edge에 배포합니다.
4
6
 
5
7
  ---
6
8
 
7
- ## 프로젝트 생성
9
+ ## 🚀 Quick Reference (복사용)
8
10
 
9
- ```bash
10
- npm create hono@latest my-app
11
- # cloudflare-workers 템플릿 선택
11
+ ### Cloudflare Workers
12
12
 
13
- cd my-app
14
- npm install
13
+ ```typescript
14
+ // nitro.config.ts
15
+ import { defineNitroConfig } from "nitro/config";
16
+
17
+ export default defineNitroConfig({
18
+ preset: "cloudflare_module",
19
+ compatibilityDate: "2024-09-19",
20
+ cloudflare: {
21
+ deployConfig: true,
22
+ nodeCompat: true,
23
+ },
24
+ });
15
25
  ```
16
26
 
17
- ---
18
-
19
- ## 프로젝트 구조
27
+ ### Cloudflare Pages
20
28
 
29
+ ```typescript
30
+ // nitro.config.ts
31
+ import { defineNitroConfig } from "nitro/config";
32
+
33
+ export default defineNitroConfig({
34
+ preset: "cloudflare_pages",
35
+ compatibilityDate: "2024-09-19",
36
+ cloudflare: {
37
+ deployConfig: true,
38
+ nodeCompat: true,
39
+ },
40
+ });
21
41
  ```
22
- my-app/
23
- ├── src/
24
- │ └── index.ts
25
- ├── wrangler.toml
26
- ├── package.json
27
- └── tsconfig.json
42
+
43
+ ```bash
44
+ # Wrangler CLI 배포
45
+ wrangler login
46
+ wrangler deploy
28
47
  ```
29
48
 
30
49
  ---
31
50
 
32
- ## 기본 설정
51
+ ## Cloudflare Workers vs Pages
52
+
53
+ | 기능 | Workers | Pages |
54
+ |------|---------|-------|
55
+ | 용도 | 순수 API/서버리스 | 정적 사이트 + API |
56
+ | 정적 파일 | ❌ | ✅ |
57
+ | 무료 요청 | 100,000/일 | 무제한 정적 |
58
+ | 커스텀 도메인 | ✅ | ✅ |
59
+ | D1/KV/R2 | ✅ | ✅ |
60
+
61
+ ---
62
+
63
+ ## Cloudflare Workers 설정
64
+
65
+ ### nitro.config.ts
66
+
67
+ ```typescript
68
+ // nitro.config.ts
69
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
70
+ // Cloudflare Workers 배포용 Nitro 설정
71
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
72
+ import { defineNitroConfig } from "nitro/config";
73
+
74
+ export default defineNitroConfig({
75
+ // Cloudflare Workers (ES Module 형식)
76
+ preset: "cloudflare_module",
77
+
78
+ // 호환성 날짜 (필수)
79
+ compatibilityDate: "2024-09-19",
80
+
81
+ // Cloudflare 설정
82
+ cloudflare: {
83
+ // wrangler.toml 자동 생성
84
+ deployConfig: true,
85
+
86
+ // Node.js 호환성 활성화
87
+ nodeCompat: true,
88
+ },
89
+ });
90
+ ```
33
91
 
34
92
  ### wrangler.toml
35
93
 
36
94
  ```toml
37
- name = "my-hono-app"
38
- main = "src/index.ts"
39
- compatibility_date = "2024-01-01"
95
+ # wrangler.toml
96
+ # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
97
+ # Cloudflare Workers 설정
98
+ # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
99
+
100
+ name = "hono-nitro-app"
101
+ main = ".output/server/index.mjs"
102
+ compatibility_date = "2024-09-19"
103
+
104
+ # Node.js 호환성 플래그
40
105
  compatibility_flags = ["nodejs_compat"]
41
106
 
107
+ # 환경 변수
42
108
  [vars]
43
109
  NODE_ENV = "production"
44
110
 
45
- # KV Namespace
46
- [[kv_namespaces]]
47
- binding = "MY_KV"
48
- id = "your-kv-namespace-id"
49
-
50
- # D1 Database
111
+ # D1 데이터베이스 바인딩
51
112
  [[d1_databases]]
52
113
  binding = "DB"
53
114
  database_name = "my-database"
54
- database_id = "your-database-id"
115
+ database_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
116
+
117
+ # KV 네임스페이스 바인딩
118
+ [[kv_namespaces]]
119
+ binding = "KV"
120
+ id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
55
121
 
56
- # R2 Bucket
122
+ # R2 버킷 바인딩
57
123
  [[r2_buckets]]
58
- binding = "MY_BUCKET"
124
+ binding = "BUCKET"
59
125
  bucket_name = "my-bucket"
126
+
127
+ # 시크릿 (wrangler secret put 으로 설정)
128
+ # API_SECRET = "..."
60
129
  ```
61
130
 
62
- ### src/index.ts
131
+ ---
132
+
133
+ ## Cloudflare Pages 설정
134
+
135
+ ### nitro.config.ts
63
136
 
64
137
  ```typescript
65
- import { Hono } from 'hono'
138
+ // nitro.config.ts
139
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
140
+ // Cloudflare Pages 배포용 Nitro 설정
141
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
142
+ import { defineNitroConfig } from "nitro/config";
143
+
144
+ export default defineNitroConfig({
145
+ // Cloudflare Pages
146
+ preset: "cloudflare_pages",
147
+
148
+ // 호환성 날짜
149
+ compatibilityDate: "2024-09-19",
150
+
151
+ // Cloudflare 설정
152
+ cloudflare: {
153
+ deployConfig: true,
154
+ nodeCompat: true,
155
+
156
+ // Pages 전용 설정
157
+ pages: {
158
+ // 정적 파일 디렉토리
159
+ staticDir: "public",
160
+ },
161
+ },
162
+ });
163
+ ```
66
164
 
67
- type Bindings = {
68
- NODE_ENV: string
69
- MY_KV: KVNamespace
70
- DB: D1Database
71
- MY_BUCKET: R2Bucket
72
- }
165
+ ---
166
+
167
+ ## 배포 방법
168
+
169
+ ### 방법 1: Wrangler CLI (Workers)
170
+
171
+ ```bash
172
+ # Wrangler CLI 설치
173
+ npm install -g wrangler
174
+
175
+ # 로그인
176
+ wrangler login
73
177
 
74
- const app = new Hono<{ Bindings: Bindings }>()
178
+ # 빌드
179
+ yarn build
75
180
 
76
- app.get('/', (c) => {
77
- return c.json({ message: 'Hello Cloudflare Workers!' })
78
- })
181
+ # 배포
182
+ wrangler deploy
79
183
 
80
- export default app
184
+ # 개발 서버
185
+ wrangler dev
81
186
  ```
82
187
 
83
- ---
188
+ ### 방법 2: GitHub 연동 (Pages)
84
189
 
85
- ## Bindings 사용
190
+ 1. **Cloudflare Pages 프로젝트 생성**
191
+ - [Cloudflare Dashboard](https://dash.cloudflare.com) → Pages
192
+ - "Create a project" → "Connect to Git"
193
+ - GitHub 저장소 선택
86
194
 
87
- ### KV Namespace
195
+ 2. **빌드 설정**
196
+ ```
197
+ Framework preset: None
198
+ Build command: yarn build
199
+ Build output directory: .output/public
200
+ ```
88
201
 
89
- ```typescript
90
- app.get('/kv/:key', async (c) => {
91
- const key = c.req.param('key')
92
- const value = await c.env.MY_KV.get(key)
93
- return c.json({ key, value })
94
- })
95
-
96
- app.put('/kv/:key', async (c) => {
97
- const key = c.req.param('key')
98
- const { value } = await c.req.json()
99
- await c.env.MY_KV.put(key, value)
100
- return c.json({ success: true })
101
- })
202
+ 3. **환경 변수 설정**
203
+ - Settings Environment variables
204
+
205
+ ### 방법 3: Wrangler CLI (Pages)
206
+
207
+ ```bash
208
+ # Pages 배포
209
+ wrangler pages deploy .output/public
210
+
211
+ # 프로덕션 배포
212
+ wrangler pages deploy .output/public --branch main
102
213
  ```
103
214
 
104
- ### D1 Database
215
+ ---
216
+
217
+ ## Bindings (D1, KV, R2)
218
+
219
+ ### D1 데이터베이스
105
220
 
106
221
  ```typescript
107
- app.get('/users', async (c) => {
222
+ // src/server.ts
223
+ import { Hono } from "hono";
224
+
225
+ // Cloudflare Bindings 타입 정의
226
+ type Bindings = {
227
+ DB: D1Database;
228
+ };
229
+
230
+ const app = new Hono<{ Bindings: Bindings }>();
231
+
232
+ // D1 쿼리
233
+ app.get("/users", async (c) => {
108
234
  const { results } = await c.env.DB.prepare(
109
- 'SELECT * FROM users'
110
- ).all()
111
- return c.json({ users: results })
112
- })
113
-
114
- app.post('/users', async (c) => {
115
- const { name, email } = await c.req.json()
116
- const { success } = await c.env.DB.prepare(
117
- 'INSERT INTO users (name, email) VALUES (?, ?)'
118
- ).bind(name, email).run()
119
- return c.json({ success }, 201)
120
- })
121
- ```
235
+ "SELECT * FROM users"
236
+ ).all();
122
237
 
123
- ### R2 Bucket
238
+ return c.json(results);
239
+ });
124
240
 
125
- ```typescript
126
- app.put('/upload/:key', async (c) => {
127
- const key = c.req.param('key')
128
- await c.env.MY_BUCKET.put(key, c.req.body)
129
- return c.json({ success: true })
130
- })
241
+ app.post("/users", async (c) => {
242
+ const { name, email } = await c.req.json();
131
243
 
132
- app.get('/download/:key', async (c) => {
133
- const key = c.req.param('key')
134
- const object = await c.env.MY_BUCKET.get(key)
244
+ const result = await c.env.DB.prepare(
245
+ "INSERT INTO users (name, email) VALUES (?, ?)"
246
+ )
247
+ .bind(name, email)
248
+ .run();
135
249
 
136
- if (!object) {
137
- return c.notFound()
138
- }
250
+ return c.json({ id: result.meta.last_row_id });
251
+ });
139
252
 
140
- return new Response(object.body, {
141
- headers: {
142
- 'Content-Type': object.httpMetadata?.contentType || 'application/octet-stream',
143
- },
144
- })
145
- })
253
+ export default app;
146
254
  ```
147
255
 
148
- ---
256
+ ### D1 마이그레이션
149
257
 
150
- ## 환경 변수
258
+ ```bash
259
+ # 마이그레이션 생성
260
+ wrangler d1 migrations create my-database create_users
151
261
 
152
- ### 로컬 개발 (.dev.vars)
262
+ # 마이그레이션 적용
263
+ wrangler d1 migrations apply my-database
153
264
 
265
+ # 로컬 D1 실행
266
+ wrangler d1 execute my-database --local --command="SELECT * FROM users"
154
267
  ```
155
- DATABASE_URL=postgresql://...
156
- JWT_SECRET=dev-secret
157
- API_KEY=dev-api-key
268
+
269
+ ```sql
270
+ -- migrations/0001_create_users.sql
271
+ CREATE TABLE users (
272
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
273
+ name TEXT NOT NULL,
274
+ email TEXT UNIQUE NOT NULL,
275
+ created_at DATETIME DEFAULT CURRENT_TIMESTAMP
276
+ );
158
277
  ```
159
278
 
160
- ### 시크릿 설정
279
+ ### KV 스토리지
161
280
 
162
- ```bash
163
- # 시크릿 추가
164
- npx wrangler secret put JWT_SECRET
165
- npx wrangler secret put DATABASE_URL
281
+ ```typescript
282
+ // src/server.ts
283
+ import { Hono } from "hono";
166
284
 
167
- # 시크릿 목록
168
- npx wrangler secret list
285
+ type Bindings = {
286
+ KV: KVNamespace;
287
+ };
169
288
 
170
- # 시크릿 삭제
171
- npx wrangler secret delete JWT_SECRET
172
- ```
289
+ const app = new Hono<{ Bindings: Bindings }>();
173
290
 
174
- ---
291
+ // KV 읽기
292
+ app.get("/cache/:key", async (c) => {
293
+ const key = c.req.param("key");
294
+ const value = await c.env.KV.get(key);
175
295
 
176
- ## 타입 생성
296
+ if (!value) {
297
+ return c.json({ error: "Not found" }, 404);
298
+ }
177
299
 
178
- ```bash
179
- # wrangler.toml 기반 타입 생성
180
- npx wrangler types
300
+ return c.json({ key, value: JSON.parse(value) });
301
+ });
302
+
303
+ // KV 쓰기
304
+ app.put("/cache/:key", async (c) => {
305
+ const key = c.req.param("key");
306
+ const body = await c.req.json();
181
307
 
182
- # 또는 환경별 타입 생성
183
- npx wrangler types --env-interface CloudflareBindings
308
+ // TTL 설정 (초 단위)
309
+ await c.env.KV.put(key, JSON.stringify(body), {
310
+ expirationTtl: 3600, // 1시간
311
+ });
312
+
313
+ return c.json({ success: true });
314
+ });
315
+
316
+ export default app;
184
317
  ```
185
318
 
186
- ### worker-configuration.d.ts
319
+ ### R2 스토리지
187
320
 
188
321
  ```typescript
189
- interface CloudflareBindings {
190
- NODE_ENV: string
191
- MY_KV: KVNamespace
192
- DB: D1Database
193
- MY_BUCKET: R2Bucket
194
- JWT_SECRET: string
195
- }
196
- ```
322
+ // src/server.ts
323
+ import { Hono } from "hono";
324
+
325
+ type Bindings = {
326
+ BUCKET: R2Bucket;
327
+ };
328
+
329
+ const app = new Hono<{ Bindings: Bindings }>();
330
+
331
+ // 파일 업로드
332
+ app.post("/upload/:filename", async (c) => {
333
+ const filename = c.req.param("filename");
334
+ const body = await c.req.arrayBuffer();
335
+
336
+ await c.env.BUCKET.put(filename, body, {
337
+ httpMetadata: {
338
+ contentType: c.req.header("Content-Type") || "application/octet-stream",
339
+ },
340
+ });
341
+
342
+ return c.json({ success: true, filename });
343
+ });
197
344
 
198
- ### tsconfig.json
345
+ // 파일 다운로드
346
+ app.get("/download/:filename", async (c) => {
347
+ const filename = c.req.param("filename");
348
+ const object = await c.env.BUCKET.get(filename);
199
349
 
200
- ```json
201
- {
202
- "compilerOptions": {
203
- "types": [
204
- "@cloudflare/workers-types",
205
- "./worker-configuration.d.ts"
206
- ]
350
+ if (!object) {
351
+ return c.json({ error: "Not found" }, 404);
207
352
  }
208
- }
353
+
354
+ c.header("Content-Type", object.httpMetadata?.contentType || "application/octet-stream");
355
+ return c.body(object.body);
356
+ });
357
+
358
+ export default app;
209
359
  ```
210
360
 
211
361
  ---
212
362
 
213
- ## 배포
363
+ ## 환경 변수
214
364
 
215
- ### 개발 서버
365
+ ### wrangler.toml에서 설정
216
366
 
217
- ```bash
218
- npm run dev
219
- # 또는
220
- npx wrangler dev
367
+ ```toml
368
+ # wrangler.toml
369
+ [vars]
370
+ NODE_ENV = "production"
371
+ API_BASE_URL = "https://api.example.com"
372
+
373
+ # 환경별 설정
374
+ [env.staging.vars]
375
+ NODE_ENV = "staging"
376
+ API_BASE_URL = "https://staging-api.example.com"
377
+
378
+ [env.production.vars]
379
+ NODE_ENV = "production"
380
+ API_BASE_URL = "https://api.example.com"
221
381
  ```
222
382
 
223
- ### 프로덕션 배포
383
+ ### 시크릿 설정 (CLI)
224
384
 
225
385
  ```bash
226
- npm run deploy
227
- # 또는
228
- npx wrangler deploy
386
+ # 시크릿 추가
387
+ wrangler secret put API_SECRET
388
+ wrangler secret put DATABASE_URL
389
+
390
+ # 시크릿 목록
391
+ wrangler secret list
392
+
393
+ # 시크릿 삭제
394
+ wrangler secret delete API_SECRET
229
395
  ```
230
396
 
231
- ### 환경별 배포
397
+ ### 코드에서 사용
232
398
 
233
- ```bash
234
- # staging
235
- npx wrangler deploy --env staging
399
+ ```typescript
400
+ // src/server.ts
401
+ import { Hono } from "hono";
236
402
 
237
- # production
238
- npx wrangler deploy --env production
403
+ type Bindings = {
404
+ API_SECRET: string;
405
+ NODE_ENV: string;
406
+ };
407
+
408
+ const app = new Hono<{ Bindings: Bindings }>();
409
+
410
+ app.get("/config", (c) => {
411
+ return c.json({
412
+ environment: c.env.NODE_ENV,
413
+ hasSecret: !!c.env.API_SECRET,
414
+ });
415
+ });
416
+
417
+ export default app;
239
418
  ```
240
419
 
241
- ### wrangler.toml (환경별)
420
+ ---
242
421
 
243
- ```toml
244
- name = "my-app"
245
- main = "src/index.ts"
422
+ ## 도메인 설정
246
423
 
247
- [env.staging]
248
- name = "my-app-staging"
249
- vars = { NODE_ENV = "staging" }
424
+ ### Workers 커스텀 도메인
250
425
 
251
- [env.production]
252
- name = "my-app-production"
253
- vars = { NODE_ENV = "production" }
426
+ ```toml
427
+ # wrangler.toml
428
+ routes = [
429
+ { pattern = "api.example.com/*", zone_name = "example.com" }
430
+ ]
431
+
432
+ # 또는
433
+ [triggers]
434
+ routes = [
435
+ "api.example.com/*"
436
+ ]
254
437
  ```
255
438
 
439
+ ### Pages 커스텀 도메인
440
+
441
+ 1. Cloudflare Dashboard → Pages → 프로젝트 선택
442
+ 2. Custom domains → Add custom domain
443
+ 3. DNS 설정 자동 구성
444
+
256
445
  ---
257
446
 
258
- ## GitHub Actions
447
+ ## CI/CD 설정
448
+
449
+ ### GitHub Actions (Workers)
259
450
 
260
451
  ```yaml
452
+ # .github/workflows/cloudflare-workers.yml
261
453
  name: Deploy to Cloudflare Workers
262
454
 
263
455
  on:
264
456
  push:
265
- branches:
266
- - main
457
+ branches: [main]
267
458
 
268
459
  jobs:
269
460
  deploy:
270
461
  runs-on: ubuntu-latest
462
+
271
463
  steps:
272
464
  - uses: actions/checkout@v4
273
465
 
274
466
  - name: Setup Node.js
275
467
  uses: actions/setup-node@v4
276
468
  with:
277
- node-version: '20'
469
+ node-version: "20"
470
+ cache: "yarn"
278
471
 
279
472
  - name: Install dependencies
280
- run: npm ci
473
+ run: yarn install --frozen-lockfile
474
+
475
+ - name: Build
476
+ run: yarn build
281
477
 
282
- - name: Deploy
478
+ - name: Deploy to Cloudflare Workers
283
479
  uses: cloudflare/wrangler-action@v3
284
480
  with:
285
481
  apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
286
- # 환경 지정 시
287
- # command: deploy --env production
288
482
  ```
289
483
 
290
- ### GitHub Secrets 설정
484
+ ### GitHub Actions (Pages)
485
+
486
+ ```yaml
487
+ # .github/workflows/cloudflare-pages.yml
488
+ name: Deploy to Cloudflare Pages
489
+
490
+ on:
491
+ push:
492
+ branches: [main]
493
+
494
+ jobs:
495
+ deploy:
496
+ runs-on: ubuntu-latest
497
+
498
+ steps:
499
+ - uses: actions/checkout@v4
500
+
501
+ - name: Setup Node.js
502
+ uses: actions/setup-node@v4
503
+ with:
504
+ node-version: "20"
505
+ cache: "yarn"
506
+
507
+ - name: Install dependencies
508
+ run: yarn install --frozen-lockfile
509
+
510
+ - name: Build
511
+ run: yarn build
512
+
513
+ - name: Deploy to Cloudflare Pages
514
+ uses: cloudflare/pages-action@v1
515
+ with:
516
+ apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
517
+ accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
518
+ projectName: my-hono-app
519
+ directory: .output/public
520
+ branch: main
521
+ ```
522
+
523
+ ---
524
+
525
+ ## 성능 최적화
526
+
527
+ ### 캐싱 설정
528
+
529
+ ```typescript
530
+ // src/server.ts
531
+ import { Hono } from "hono";
532
+ import { cache } from "hono/cache";
533
+
534
+ const app = new Hono();
535
+
536
+ // 캐시 미들웨어
537
+ app.use(
538
+ "/api/public/*",
539
+ cache({
540
+ cacheName: "hono-cache",
541
+ cacheControl: "max-age=3600", // 1시간
542
+ })
543
+ );
544
+
545
+ // 또는 수동으로 Cache API 사용
546
+ app.get("/cached-data", async (c) => {
547
+ const cacheKey = new Request(c.req.url);
548
+ const cache = caches.default;
549
+
550
+ // 캐시 확인
551
+ let response = await cache.match(cacheKey);
552
+ if (response) {
553
+ return response;
554
+ }
555
+
556
+ // 데이터 가져오기
557
+ const data = await fetchData();
558
+
559
+ // 응답 생성 및 캐시
560
+ response = c.json(data);
561
+ response.headers.set("Cache-Control", "max-age=3600");
562
+
563
+ c.executionCtx.waitUntil(cache.put(cacheKey, response.clone()));
564
+
565
+ return response;
566
+ });
567
+
568
+ export default app;
569
+ ```
570
+
571
+ ### Smart Placement
572
+
573
+ ```toml
574
+ # wrangler.toml
575
+ # Smart Placement: 데이터 소스에 가까운 위치에서 실행
576
+ [placement]
577
+ mode = "smart"
578
+ ```
579
+
580
+ ---
581
+
582
+ ## 로컬 개발
583
+
584
+ ### Wrangler Dev
585
+
586
+ ```bash
587
+ # 로컬 개발 서버
588
+ wrangler dev
589
+
590
+ # D1 로컬 모드
591
+ wrangler dev --local --persist
592
+
593
+ # 특정 포트
594
+ wrangler dev --port 3000
595
+ ```
596
+
597
+ ### Miniflare (고급)
291
598
 
292
- 1. Cloudflare Dashboard → My Profile → API Tokens
293
- 2. "Create Token" → "Edit Cloudflare Workers" 템플릿 사용
294
- 3. GitHub Repository Settings → Secrets → `CLOUDFLARE_API_TOKEN` 추가
599
+ ```typescript
600
+ // miniflare.config.ts
601
+ import { Miniflare } from "miniflare";
602
+
603
+ const mf = new Miniflare({
604
+ script: ".output/server/index.mjs",
605
+ modules: true,
606
+ d1Databases: ["DB"],
607
+ kvNamespaces: ["KV"],
608
+ r2Buckets: ["BUCKET"],
609
+ });
610
+ ```
295
611
 
296
612
  ---
297
613
 
298
- ## 로깅 및 모니터링
614
+ ## 문제 해결
299
615
 
300
- ### 실시간 로그
616
+ ### 일반적인 문제
617
+
618
+ | 문제 | 원인 | 해결 |
619
+ |------|------|------|
620
+ | "Worker exceeded size limit" | 번들 크기 초과 | 의존성 최적화, externals 설정 |
621
+ | "D1 not found" | 바인딩 설정 오류 | wrangler.toml 확인 |
622
+ | "Compatibility date" 오류 | 날짜 형식 오류 | YYYY-MM-DD 형식 확인 |
623
+ | Node.js API 오류 | 호환성 플래그 누락 | `nodejs_compat` 플래그 추가 |
624
+
625
+ ### 디버깅
301
626
 
302
627
  ```bash
303
- npx wrangler tail
628
+ # 로그 확인 (실시간)
629
+ wrangler tail
630
+
631
+ # 배포 상태 확인
632
+ wrangler deployments list
633
+
634
+ # 설정 검증
635
+ wrangler deploy --dry-run
304
636
  ```
305
637
 
306
- ### 커스텀 로깅
638
+ ### 번들 크기 최적화
307
639
 
308
640
  ```typescript
309
- app.use(async (c, next) => {
310
- const start = Date.now()
311
- await next()
312
- const duration = Date.now() - start
313
-
314
- console.log({
315
- method: c.req.method,
316
- path: c.req.path,
317
- status: c.res.status,
318
- duration: `${duration}ms`,
319
- })
320
- })
641
+ // nitro.config.ts
642
+ import { defineNitroConfig } from "nitro/config";
643
+
644
+ export default defineNitroConfig({
645
+ preset: "cloudflare_module",
646
+ compatibilityDate: "2024-09-19",
647
+
648
+ // 외부 패키지 제외
649
+ externals: ["@prisma/client"],
650
+
651
+ // 압축
652
+ minify: true,
653
+ });
321
654
  ```
322
655
 
323
656
  ---
324
657
 
325
658
  ## 관련 문서
326
659
 
327
- - [배포 개요](./index.md)
328
- - [Hono 기본](../library/hono/index.md)
660
+ - [배포 가이드 개요](./index.md)
661
+ - [Docker 배포](./docker.md)
662
+ - [Railway 배포](./railway.md)
663
+ - [Vercel 배포](./vercel.md)
664
+ - [Cloudflare Workers 공식 문서](https://developers.cloudflare.com/workers/)
665
+ - [Cloudflare Pages 공식 문서](https://developers.cloudflare.com/pages/)