@kood/claude-code 0.1.1 → 0.1.3

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 (61) hide show
  1. package/dist/index.js +81 -38
  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/deployment/cloudflare.md +537 -190
  6. package/templates/hono/docs/deployment/docker.md +517 -0
  7. package/templates/hono/docs/deployment/index.md +181 -213
  8. package/templates/hono/docs/deployment/railway.md +416 -0
  9. package/templates/hono/docs/deployment/vercel.md +572 -0
  10. package/templates/hono/docs/git/git.md +285 -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 -0
  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/git/git.md +307 -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/deployment/cloudflare.md +234 -51
  38. package/templates/tanstack-start/docs/deployment/index.md +322 -32
  39. package/templates/tanstack-start/docs/deployment/nitro.md +201 -20
  40. package/templates/tanstack-start/docs/deployment/railway.md +305 -153
  41. package/templates/tanstack-start/docs/deployment/vercel.md +353 -78
  42. package/templates/tanstack-start/docs/git/{index.md → git.md} +81 -7
  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 -1
  56. package/templates/tanstack-start/docs/library/prisma/schema.md +123 -25
  57. package/templates/tanstack-start/docs/library/tanstack-start/server-functions.md +80 -2
  58. package/templates/tanstack-start/docs/skills/gemini-review/SKILL.md +116 -116
  59. package/templates/tanstack-start/docs/skills/gemini-review/references/checklists.md +138 -144
  60. package/templates/tanstack-start/docs/skills/gemini-review/references/prompt-templates.md +186 -187
  61. package/templates/hono/docs/git/index.md +0 -180
@@ -1,328 +1,675 @@
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"
55
116
 
56
- # R2 Bucket
117
+ # KV 네임스페이스 바인딩
118
+ [[kv_namespaces]]
119
+ binding = "KV"
120
+ id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
121
+
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
73
174
 
74
- const app = new Hono<{ Bindings: Bindings }>()
175
+ # 로그인
176
+ wrangler login
75
177
 
76
- app.get('/', (c) => {
77
- return c.json({ message: 'Hello Cloudflare Workers!' })
78
- })
178
+ # 빌드
179
+ pnpm build
79
180
 
80
- export default app
181
+ # 배포
182
+ wrangler deploy
183
+
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: pnpm 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
+ });
181
302
 
182
- # 또는 환경별 타입 생성
183
- npx wrangler types --env-interface CloudflareBindings
303
+ // KV 쓰기
304
+ app.put("/cache/:key", async (c) => {
305
+ const key = c.req.param("key");
306
+ const body = await c.req.json();
307
+
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";
402
+
403
+ type Bindings = {
404
+ API_SECRET: string;
405
+ NODE_ENV: string;
406
+ };
407
+
408
+ const app = new Hono<{ Bindings: Bindings }>();
236
409
 
237
- # production
238
- npx wrangler deploy --env production
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
 
466
+ - name: Setup pnpm
467
+ uses: pnpm/action-setup@v2
468
+ with:
469
+ version: 8
470
+
274
471
  - name: Setup Node.js
275
472
  uses: actions/setup-node@v4
276
473
  with:
277
- node-version: '20'
474
+ node-version: "20"
475
+ cache: "pnpm"
278
476
 
279
477
  - name: Install dependencies
280
- run: npm ci
478
+ run: pnpm install
479
+
480
+ - name: Build
481
+ run: pnpm build
281
482
 
282
- - name: Deploy
483
+ - name: Deploy to Cloudflare Workers
283
484
  uses: cloudflare/wrangler-action@v3
284
485
  with:
285
486
  apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
286
- # 환경 지정 시
287
- # command: deploy --env production
288
487
  ```
289
488
 
290
- ### GitHub Secrets 설정
489
+ ### GitHub Actions (Pages)
490
+
491
+ ```yaml
492
+ # .github/workflows/cloudflare-pages.yml
493
+ name: Deploy to Cloudflare Pages
494
+
495
+ on:
496
+ push:
497
+ branches: [main]
498
+
499
+ jobs:
500
+ deploy:
501
+ runs-on: ubuntu-latest
502
+
503
+ steps:
504
+ - uses: actions/checkout@v4
505
+
506
+ - name: Setup pnpm
507
+ uses: pnpm/action-setup@v2
508
+ with:
509
+ version: 8
510
+
511
+ - name: Setup Node.js
512
+ uses: actions/setup-node@v4
513
+ with:
514
+ node-version: "20"
515
+ cache: "pnpm"
516
+
517
+ - name: Install dependencies
518
+ run: pnpm install
519
+
520
+ - name: Build
521
+ run: pnpm build
522
+
523
+ - name: Deploy to Cloudflare Pages
524
+ uses: cloudflare/pages-action@v1
525
+ with:
526
+ apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
527
+ accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
528
+ projectName: my-hono-app
529
+ directory: .output/public
530
+ branch: main
531
+ ```
532
+
533
+ ---
534
+
535
+ ## 성능 최적화
536
+
537
+ ### 캐싱 설정
538
+
539
+ ```typescript
540
+ // src/server.ts
541
+ import { Hono } from "hono";
542
+ import { cache } from "hono/cache";
543
+
544
+ const app = new Hono();
545
+
546
+ // 캐시 미들웨어
547
+ app.use(
548
+ "/api/public/*",
549
+ cache({
550
+ cacheName: "hono-cache",
551
+ cacheControl: "max-age=3600", // 1시간
552
+ })
553
+ );
291
554
 
292
- 1. Cloudflare Dashboard My Profile → API Tokens
293
- 2. "Create Token" "Edit Cloudflare Workers" 템플릿 사용
294
- 3. GitHub Repository Settings → Secrets → `CLOUDFLARE_API_TOKEN` 추가
555
+ // 또는 수동으로 Cache API 사용
556
+ app.get("/cached-data", async (c) => {
557
+ const cacheKey = new Request(c.req.url);
558
+ const cache = caches.default;
559
+
560
+ // 캐시 확인
561
+ let response = await cache.match(cacheKey);
562
+ if (response) {
563
+ return response;
564
+ }
565
+
566
+ // 데이터 가져오기
567
+ const data = await fetchData();
568
+
569
+ // 응답 생성 및 캐시
570
+ response = c.json(data);
571
+ response.headers.set("Cache-Control", "max-age=3600");
572
+
573
+ c.executionCtx.waitUntil(cache.put(cacheKey, response.clone()));
574
+
575
+ return response;
576
+ });
577
+
578
+ export default app;
579
+ ```
580
+
581
+ ### Smart Placement
582
+
583
+ ```toml
584
+ # wrangler.toml
585
+ # Smart Placement: 데이터 소스에 가까운 위치에서 실행
586
+ [placement]
587
+ mode = "smart"
588
+ ```
295
589
 
296
590
  ---
297
591
 
298
- ## 로깅 및 모니터링
592
+ ## 로컬 개발
299
593
 
300
- ### 실시간 로그
594
+ ### Wrangler Dev
301
595
 
302
596
  ```bash
303
- npx wrangler tail
597
+ # 로컬 개발 서버
598
+ wrangler dev
599
+
600
+ # D1 로컬 모드
601
+ wrangler dev --local --persist
602
+
603
+ # 특정 포트
604
+ wrangler dev --port 3000
304
605
  ```
305
606
 
306
- ### 커스텀 로깅
607
+ ### Miniflare (고급)
307
608
 
308
609
  ```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
- })
610
+ // miniflare.config.ts
611
+ import { Miniflare } from "miniflare";
612
+
613
+ const mf = new Miniflare({
614
+ script: ".output/server/index.mjs",
615
+ modules: true,
616
+ d1Databases: ["DB"],
617
+ kvNamespaces: ["KV"],
618
+ r2Buckets: ["BUCKET"],
619
+ });
620
+ ```
621
+
622
+ ---
623
+
624
+ ## 문제 해결
625
+
626
+ ### 일반적인 문제
627
+
628
+ | 문제 | 원인 | 해결 |
629
+ |------|------|------|
630
+ | "Worker exceeded size limit" | 번들 크기 초과 | 의존성 최적화, externals 설정 |
631
+ | "D1 not found" | 바인딩 설정 오류 | wrangler.toml 확인 |
632
+ | "Compatibility date" 오류 | 날짜 형식 오류 | YYYY-MM-DD 형식 확인 |
633
+ | Node.js API 오류 | 호환성 플래그 누락 | `nodejs_compat` 플래그 추가 |
634
+
635
+ ### 디버깅
636
+
637
+ ```bash
638
+ # 로그 확인 (실시간)
639
+ wrangler tail
640
+
641
+ # 배포 상태 확인
642
+ wrangler deployments list
643
+
644
+ # 설정 검증
645
+ wrangler deploy --dry-run
646
+ ```
647
+
648
+ ### 번들 크기 최적화
649
+
650
+ ```typescript
651
+ // nitro.config.ts
652
+ import { defineNitroConfig } from "nitro/config";
653
+
654
+ export default defineNitroConfig({
655
+ preset: "cloudflare_module",
656
+ compatibilityDate: "2024-09-19",
657
+
658
+ // 외부 패키지 제외
659
+ externals: ["@prisma/client"],
660
+
661
+ // 압축
662
+ minify: true,
663
+ });
321
664
  ```
322
665
 
323
666
  ---
324
667
 
325
668
  ## 관련 문서
326
669
 
327
- - [배포 개요](./index.md)
328
- - [Hono 기본](../library/hono/index.md)
670
+ - [배포 가이드 개요](./index.md)
671
+ - [Docker 배포](./docker.md)
672
+ - [Railway 배포](./railway.md)
673
+ - [Vercel 배포](./vercel.md)
674
+ - [Cloudflare Workers 공식 문서](https://developers.cloudflare.com/workers/)
675
+ - [Cloudflare Pages 공식 문서](https://developers.cloudflare.com/pages/)