Cloudflare Pages
注意
新しいプロジェクトでは、Cloudflare は現在、Cloudflare Pages よりも Cloudflare Workers を推奨しています。Workers は静的アセットに対応し、より幅広い機能を提供します。新しいフルスタックアプリケーションを始める場合は、この Pages 構成の後継となる Cloudflare Workers + Vite を参照してください。hono/cloudflare-pages アダプターは非推奨で、Hono v5 で削除される予定です。
Cloudflare Pages はフルスタック Web アプリケーション向けのエッジプラットフォームです。 静的ファイルと、Cloudflare Workers が生成する動的コンテンツを配信します。
Hono は Cloudflare Pages を完全にサポートしています。 快適な開発体験を提供します。Vite の開発サーバーは高速で、Wrangler を使ったデプロイも非常にすばやく行えます。
1. セットアップ
Cloudflare Pages 向けのスターターテンプレートがあります。 「create-hono」コマンドでプロジェクトを開始します。 この例では cloudflare-pages テンプレートを選択します。
npm create hono@latest my-appyarn create hono my-apppnpm create hono my-appbun create hono@latest my-appdeno init --npm hono my-appmy-app に移動して依存関係をインストールします。
cd my-app
npm icd my-app
yarncd my-app
pnpm icd my-app
bun i基本的なディレクトリ構成は次のとおりです。
./
├── package.json
├── public
│ └── static // Put your static files.
│ └── style.css // You can refer to it as `/static/style.css`.
├── src
│ ├── index.tsx // The entry point for server-side.
│ └── renderer.tsx
├── tsconfig.json
└── vite.config.ts2. Hello World
次のように src/index.tsx を編集します。
import { Hono } from 'hono'
import { renderer } from './renderer'
const app = new Hono()
app.get('*', renderer)
app.get('/', (c) => {
return c.render(<h1>Hello, Cloudflare Pages!</h1>)
})
export default app3. 実行
開発サーバーをローカルで起動し、Web ブラウザーで http://localhost:5173 にアクセスします。
npm run devyarn devpnpm devbun run dev4. デプロイ
Cloudflare アカウントがあれば、Cloudflare にデプロイできます。package.json の $npm_execpath は、使用するパッケージマネージャーに変更する必要があります。
npm run deployyarn deploypnpm run deploybun run deployGitHub を使って Cloudflare ダッシュボードからデプロイする
- Cloudflare ダッシュボードにログインし、アカウントを選択します。
- アカウントのホームで Workers & Pages > Create application > Pages > Connect to Git を選択します。
- GitHub アカウントを認証し、リポジトリを選択します。Set up builds and deployments で、次の情報を入力します。
| 設定項目 | 値 |
|---|---|
| 本番ブランチ | main |
| ビルドコマンド | npm run build |
| ビルドディレクトリ | dist |
バインディング
変数、KV、D1 などの Cloudflare バインディングを利用できます。 このセクションでは、変数と KV を使います。
wrangler.toml の作成
まず、ローカルのバインディング用に wrangler.toml を作成します。
touch wrangler.tomlwrangler.toml を編集し、MY_NAME という名前の変数を指定します。
[vars]
MY_NAME = "Hono"KV の作成
次に KV を作成します。以下の wrangler コマンドを実行してください。
wrangler kv namespace create MY_KV --preview次の出力にある preview_id を控えておきます。
{ binding = "MY_KV", preview_id = "abcdef" }preview_id とバインディング名 MY_KV を指定します。
[[kv_namespaces]]
binding = "MY_KV"
id = "abcdef"vite.config.ts の編集
vite.config.ts を編集します。
import devServer from '@hono/vite-dev-server'
import adapter from '@hono/vite-dev-server/cloudflare'
import build from '@hono/vite-cloudflare-pages'
import { defineConfig } from 'vite'
export default defineConfig({
plugins: [
devServer({
entry: 'src/index.tsx',
adapter, // Cloudflare Adapter
}),
build(),
],
})アプリケーションでバインディングを使う
アプリケーションで変数と KV を使い、型を設定します。
type Bindings = {
MY_NAME: string
MY_KV: KVNamespace
}
const app = new Hono<{ Bindings: Bindings }>()次のように利用します。
app.get('/', async (c) => {
await c.env.MY_KV.put('name', c.env.MY_NAME)
const name = await c.env.MY_KV.get('name')
return c.render(<h1>Hello! {name}</h1>)
})本番環境
Cloudflare Pages では、ローカル開発に wrangler.toml を使い、本番環境のバインディングはダッシュボードで設定します。
クライアント側
Vite の機能を使ってクライアント側のスクリプトを作成し、アプリケーションにインポートできます。 クライアントのエントリーポイントが /src/client.ts なら、script タグに指定するだけです。 また、import.meta.env.PROD を使うと、開発サーバーで実行されているか、ビルド段階かを判別できます。
app.get('/', (c) => {
return c.html(
<html>
<head>
{import.meta.env.PROD ? (
<script type='module' src='/static/client.js'></script>
) : (
<script type='module' src='/src/client.ts'></script>
)}
</head>
<body>
<h1>Hello</h1>
</body>
</html>
)
})スクリプトを正しくビルドするには、次の vite.config.ts の設定例を利用できます。
import pages from '@hono/vite-cloudflare-pages'
import devServer from '@hono/vite-dev-server'
import { defineConfig } from 'vite'
export default defineConfig(({ mode }) => {
if (mode === 'client') {
return {
build: {
rollupOptions: {
input: './src/client.ts',
output: {
entryFileNames: 'static/client.js',
},
},
},
}
} else {
return {
plugins: [
pages(),
devServer({
entry: 'src/index.tsx',
}),
],
}
}
})次のコマンドでサーバーとクライアントのスクリプトをビルドできます。
vite build --mode client && vite buildCloudflare Pages のミドルウェア
Cloudflare Pages は、Hono とは異なる独自のミドルウェアシステムを使います。次のように _middleware.ts というファイルから onRequest をエクスポートすると有効になります。
// functions/_middleware.ts
export async function onRequest(pagesContext) {
console.log(`You are accessing ${pagesContext.request.url}`)
return await pagesContext.next()
}handleMiddleware を使うと、Hono のミドルウェアを Cloudflare Pages のミドルウェアとして利用できます。
// functions/_middleware.ts
import { handleMiddleware } from 'hono/cloudflare-pages'
export const onRequest = handleMiddleware(async (c, next) => {
console.log(`You are accessing ${c.req.url}`)
await next()
})Hono の組み込みミドルウェアやサードパーティのミドルウェアも使えます。たとえば Basic 認証を追加するには、Hono の Basic 認証ミドルウェアを利用できます。
// functions/_middleware.ts
import { handleMiddleware } from 'hono/cloudflare-pages'
import { basicAuth } from 'hono/basic-auth'
export const onRequest = handleMiddleware(
basicAuth({
username: 'hono',
password: 'acoolproject',
})
)複数のミドルウェアを適用したい場合は、次のように記述します。
import { handleMiddleware } from 'hono/cloudflare-pages'
// ...
export const onRequest = [
handleMiddleware(middleware1),
handleMiddleware(middleware2),
handleMiddleware(middleware3),
]EventContext へのアクセス
handleMiddleware の中では、c.env を通じて EventContext オブジェクトにアクセスできます。
// functions/_middleware.ts
import { handleMiddleware } from 'hono/cloudflare-pages'
export const onRequest = [
handleMiddleware(async (c, next) => {
c.env.eventContext.data.user = 'Joe'
await next()
}),
]その後、ハンドラー内で c.env.eventContext を通じてデータにアクセスできます。
// functions/api/[[route]].ts
import type { EventContext } from 'hono/cloudflare-pages'
import { handle } from 'hono/cloudflare-pages'
// ...
type Env = {
Bindings: {
eventContext: EventContext
}
}
const app = new Hono<Env>().basePath('/api')
app.get('/hello', (c) => {
return c.json({
message: `Hello, ${c.env.eventContext.data.user}!`, // 'Joe'
})
})
export const onRequest = handle(app)