🔥
Cloudflareに入門する
CloudflareでHonoを試してみる
Cloudflare
をはじめて使用します。Hono
をデプロイしてみます。
Cloudflare
のアカウントを作成が前提です。また、devcontainer
環境でWrangler login
を行う方法を参考にしています。
Hono
pnpm add hono
pnpm add -D wrangler
ディレクトリ構成
.
├── package.json
├── src
│ └── index.ts
├── tsconfig.json
└── wrangler.json
index.ts
import { Hono } from 'hono'
const app = new Hono()
app.get('/', (c) => {
return c.json({ message: 'Hono🔥' })
})
export default app
package.json
{
"name": "@apps/hono",
"scripts": {
"dev": "wrangler dev",
"preview": "wrangler dev server-build/index.js",
"login": "wrangler login",
"logout": "wrangler logout",
"delete": "wrangler delete",
"deploy": "wrangler deploy --minify"
},
"dependencies": {
"hono": "^4.6.20"
},
"devDependencies": {
"wrangler": "^3.107.2"
}
}
wrangler.json
{
"name": "***",
"main": "src/index.ts",
"compatibility_date": "****-**-**",
"dev": {
"ip": "0.0.0.0",
"port": 8787
}
}
ログイン
pnpm wrangler login
デプロイ
pnpm run deploy
ログアウト
pnpm wrangler logout
React Hono
pnpm add react react-dom hono @hono/zod-openapi
pnpm add -D @types/react @types/react-dom vite @hono/vite-dev-server @hono/swagger-ui wrangler cloudflare-workers
ディレクトリ構成
.
├── package.json
├── src
│ ├── app.tsx
│ ├── index.tsx
│ └── main.tsx
├── tsconfig.json
├── vite.config.ts
└── wrangler.toml
wrangler.toml
name = "***"
compatibility_date = "****-**-**"
assets = { directory = "./dist/", not_found_handling = "none" }
[dev]
ip = "0.0.0.0"
port = 8787
package.json
{
"name": "@apps/hono_react",
"type": "module",
"scripts": {
"dev": "vite --host",
"build": "vite build --mode client && vite build",
"preview": "wrangler dev server-build/index.js",
"login": "wrangler login",
"logout": "wrangler logout",
"delete": "wrangler delete",
"deploy": "pnpm build && wrangler deploy server-build/index.js"
},
"dependencies": {
"@hono/zod-openapi": "^0.18.3",
"hono": "^4.6.20",
"react": "^19.0.0",
"react-dom": "^19.0.0"
},
"devDependencies": {
"@hono/swagger-ui": "^0.5.0",
"@hono/vite-build": "^1.3.0",
"@hono/vite-dev-server": "^0.18.1",
"@types/react": "^19.0.8",
"@types/react-dom": "^19.0.3",
"cloudflare-workers": "link:@hono/vite-build/cloudflare-workers",
"vite": "^6.0.11",
"wrangler": "^3.107.2"
}
}
app.tsx
import { useState } from 'react'
import { client } from './'
const App = () => {
const [message, setMessage] = useState('')
const onSubmit = async () => {
const res = await client.$get()
const data = await res.json()
setMessage(data.message)
}
return (
<>
<h1>Hono🔥 React</h1>
<button type='button' onClick={onSubmit}>
Get Message
</button>
<h1>{message}</h1>
</>
)
}
export default App
index.tsx
import { OpenAPIHono, createRoute, z } from '@hono/zod-openapi'
import type { RouteHandler } from '@hono/zod-openapi'
import { hc } from 'hono/client'
import { swaggerUI } from '@hono/swagger-ui'
import { renderToString } from 'react-dom/server'
const app = new OpenAPIHono()
const get = createRoute({
tags: ['Hono'],
method: 'get',
path: '/',
description: 'Hono🔥 React',
responses: {
200: {
description: 'Hono🔥',
content: {
'application/json': {
schema: z.object({
message: z.string(),
}),
},
},
},
},
})
export const getHandler: RouteHandler<typeof get> = async (c) => {
return c.json({ message: 'Hono🔥 React' })
}
export const api = app.basePath('/api').openapi(get, getHandler)
// Swagger
api
.doc('/doc', {
info: {
title: 'Hono API',
version: 'v1',
},
openapi: '3.1.0',
tags: [
{
name: 'Hono',
description: 'Hono API',
},
],
})
.get('/ui', swaggerUI({ url: '/api/doc' }))
type AddType = typeof api
export const client = hc<AddType>('/').api
app.get('*', (c) => {
return c.html(
renderToString(
<html lang='en'>
<head>
<meta charSet='utf-8' />
<meta content='width=device-width, initial-scale=1' name='viewport' />
<title>Hono🔥 React</title>
{import.meta.env.PROD ? (
<script type='module' src='/static/main.js'></script>
) : (
<script type='module' src='/src/main.tsx'></script>
)}
</head>
<body>
<div id='root' />
</body>
</html>,
),
)
})
export default app
main.tsx
import { createRoot } from 'react-dom/client'
import App from './app'
const rootElement = document.getElementById('root')
const root = rootElement ? createRoot(rootElement) : console.error('Root element not found')
if (root) {
root.render(<App />)
}
デプロイ
pnpm run deploy
Demo
RPCの動作が確認できます。
const onSubmit = async () => {
const res = await client.$get()
const data = await res.json()
setMessage(data.message)
}
おわりに
はじめて、Cloudflare
を使用してみましたが、シンプルで扱いやすい印象でした。これから、Cloudflare
を使用する方の参考になれば幸いです。
Discussion