mcpField
C
cloudflare-worker-base

cloudflare-worker-base

github.com/jackspaceクラウド・DevOps1639 回インストール12 週間前に更新
リポジトリ

cloudflare-worker-base について

cloudflare-worker-base は、Cloudflare Workers 開発者向けのセットアップスキルです。Hono、Vite、Wrangler を使うプロジェクトの手順とテンプレートに加え、設定やデプロイに関する既知の問題への対処をまとめています。

主な機能

  1. 01Workers プロジェクトの作成手順
  2. 02Hono、Vite、Wrangler の設定
  3. 03設定ファイルとアプリのテンプレート
  4. 04ルーティング、静的アセット、API の設定
  5. 05開発、型生成、デプロイの手順
  6. 06既知の問題と予防策の整理

活用シーン

  1. 01Cloudflare Worker プロジェクトの新規作成
  2. 02API ルートと静的ページを含むアプリの構築
  3. 03ローカル開発と型生成の設定
  4. 04ルーティング競合やデプロイ問題の調査

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/jackspace/claudeskillz --skill cloudflare-worker-base

インストール後、Claude Code で/cloudflare-worker-baseを入力して読み込まれたか確認します。

同梱ファイルREADME.mdSKILL.json

詳細

Cloudflare Worker ベーススタック

本番環境でテスト済み:cloudflare-worker-base-test (https://cloudflare-worker-base-test.webfonts.workers.dev) 最終更新日:2025-10-20 ステータス:本番環境対応済み ✅


クイックスタート(5 分)

1. プロジェクトのひな形を作成
npm create cloudflare@latest my-worker -- \
  --type hello-world \
  --ts \
  --git \
  --deploy false \
  --framework none

これらのフラグを指定する理由:

  • --type hello-world:シンプルな出発点
  • --ts:TypeScript のサポート
  • --git:Git リポジトリを初期化
  • --deploy false:まだデプロイしない(先に設定)
  • --framework none:Vite は自分で追加します
2. 依存関係をインストール
cd my-worker
npm install [email protected]
npm install -D @cloudflare/[email protected] vite@latest

バージョンに関する注記:

  • [email protected]:最新の安定版(2025-10-20 に確認済み)
  • @cloudflare/[email protected]:最新の安定版。HMR の競合状態を修正
  • vite:Cloudflare プラグインと互換性のある最新バージョン
3. Wrangler を設定

wrangler.jsonc を作成または更新します:

{
  "$schema": "node_modules/wrangler/config-schema.json",
  "name": "my-worker",
  "main": "src/index.ts",
  "account_id": "YOUR_ACCOUNT_ID",
  "compatibility_date": "2025-10-11",
  "observability": {
    "enabled": true
  },
  "assets": {
    "directory": "./public/",
    "binding": "ASSETS",
    "not_found_handling": "single-page-application",
    "run_worker_first": ["/api/*"]
  }
}

重要:run_worker_first の設定

  • これがないと、SPA フォールバックが API ルートを横取りします
  • API ルートが JSON ではなく index.html を返します
  • 出典:workers-sdk #8879
4. Vite を設定

vite.config.ts を作成します:

import { defineConfig } from 'vite'
import { cloudflare } from '@cloudflare/vite-plugin'

export default defineConfig({
  plugins: [
    cloudflare({
      // Optional: Configure the plugin if needed
    }),
  ],
})

@cloudflare/vite-plugin を使う理由:

  • Cloudflare 公式のプラグインです
  • Workers での HMR をサポートします
  • Miniflare を使ったローカル開発を可能にします
  • バージョン 1.13.13 で「A hanging Promise was canceled」エラーが修正されています

4 つのステップでセットアップ

ステップ 1:API ルートを含む Hono アプリを作成

src/index.ts を作成します:

/**
 * Cloudflare Worker with Hono
 *
 * CRITICAL: Export pattern to prevent build errors
 * ✅ CORRECT: export default app
 * ❌ WRONG:   export default { fetch: app.fetch }
 */

import { Hono } from 'hono'

// Type-safe environment bindings
type Bindings = {
  ASSETS: Fetcher
}

const app = new Hono<{ Bindings: Bindings }>()

/**
 * API Routes
 * Handled BEFORE static assets due to run_worker_first config
 */
app.get('/api/hello', (c) => {
  return c.json({
    message: 'Hello from Cloudflare Workers!',
    timestamp: new Date().toISOString(),
  })
})

app.get('/api/health', (c) => {
  return c.json({
    status: 'ok',
    version: '1.0.0',
    environment: c.env ? 'production' : 'development',
  })
})

/**
 * Fallback to Static Assets
 * Any route not matched above is served from public/ directory
 */
app.all('*', (c) => {
  return c.env.ASSETS.fetch(c.req.raw)
})

/**
 * Export the Hono app directly (ES Module format)
 * This is the correct pattern for Cloudflare Workers with Hono + Vite
 */
export default app

このエクスポート形式を使う理由:

  • 出典:honojs/hono #3955
  • { fetch: app.fetch } を使うと、「Cannot read properties of undefined (reading 'map)」が発生します
  • 例外:scheduled/tail ハンドラーが必要な場合は、Module Worker 形式を使います:
    export default {
      fetch: app.fetch,
      scheduled: async (event, env, ctx) => { /* ... */ }
    }
    
ステップ 2:静的フロントエンドを作成

public/index.html を作成します:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>My Worker App</title>
  <link rel="stylesheet" href="/styles.css">
</head>
<body>
  <div class="container">
    <h1>Cloudflare Worker + Static Assets</h1>
    <button onclick="testAPI()">Test API</button>
    <pre id="output"></pre>
  </div>
  <script src="/script.js"></script>
</body>
</html>

public/script.js を作成します:

async function testAPI() {
  const response = await fetch('/api/hello')
  const data = await response.json()
  document.getElementById('output').textContent = JSON.stringify(data, null, 2)
}

public/styles.css を作成します:

body {
  font-family: system-ui, -apple-system, sans-serif;
  max-width: 800px;
  margin: 40px auto;
  padding: 20px;
}

button {
  background: #0070f3;
  color: white;
  border: none;
  padding: 12px 24px;
  border-radius: 6px;
  cursor: pointer;
}

pre {
  background: #f5f5f5;
  padding: 16px;
  border-radius: 6px;
  overflow-x: auto;
}
ステップ 3:パッケージスクリプトを更新

package.json を更新します:

{
  "scripts": {
    "dev": "wrangler dev",
    "deploy": "wrangler deploy",
    "cf-typegen": "wrangler types"
  }
}
ステップ 4:テストしてデプロイ
# Generate TypeScript types for bindings
npm run cf-typegen

# Start local dev server (http://localhost:8787)
npm run dev

# Deploy to production
npm run deploy

既知の問題を防ぐ

このスキルでは、文書化されている 6 つの問題を防ぎます:

問題 #1:エクスポート構文エラー

エラー:「Cannot read properties of undefined (reading 'map')」 出典:honojs/hono #3955 対策:export default app を使います({ fetch: app.fetch } は使わないでください)

問題 #2:静的アセットのルーティング競合

エラー:API ルートが JSON ではなく index.html を返す 出典:workers-sdk #8879 対策:wrangler.jsonc に "run_worker_first": ["/api/*"] を追加します

問題 #3:Scheduled/Cron がエクスポートされない

エラー:「Handler does not export a scheduled() function」 出典:honojs/vite-plugins #275 対策:必要な場合は Module Worker 形式を使います:

export default {
  fetch: app.fetch,
  scheduled: async (event, env, ctx) => { /* ... */ }
}
問題 #4:HMR の競合状態

エラー:開発中に「A hanging Promise was canceled」が発生する 出典:workers-sdk #9518 対策:@cloudflare/[email protected] 以降を使います

問題 #5:静的アセットのアップロード競合

エラー:CI/CD でデプロイが予測不能な形で失敗する 出典:workers-sdk #7555 対策:再試行ロジックを備えた Wrangler 4.x 以降を使います(最近のバージョンで修正済み)

問題 #6:Service Worker 形式の混同

エラー:非推奨の Service Worker 形式を使用する 出典:Cloudflare の移行ガイド 対策:常に ES Module 形式を使います(ステップ 1 を参照)


設定ファイルのリファレンス

wrangler.jsonc(完全な例)
{
  "$schema": "node_modules/wrangler/config-schema.json",
  "name": "my-worker",
  "main": "src/index.ts",
  "account_id": "YOUR_ACCOUNT_ID",
  "compatibility_date": "2025-10-11",
  "observability": {
    "enabled": true
  },
  "assets": {
    "directory": "./public/",
    "binding": "ASSETS",
    "not_found_handling": "single-page-application",
    "run_worker_first": ["/api/*"]
  }
  /* Optional: Environment Variables */
  // "vars": { "MY_VARIABLE": "production_value" }

  /* Optional: KV Namespace Bindings */
  // "kv_namespaces": [
  //   { "binding": "MY_KV", "id": "YOUR_KV_ID" }
  // ]

  /* Optional: D1 Database Bindings */
  // "d1_databases": [
  //   { "binding": "DB", "database_name": "my-db", "database_id": "YOUR_DB_ID" }
  // ]

  /* Optional: R2 Bucket Bindings */
  // "r2_buckets": [
  //   { "binding": "MY_BUCKET", "bucket_name": "my-bucket" }
  // ]
}

wrangler.toml ではなく wrangler.jsonc を使う理由:

  • Wrangler v3.91.0 以降は JSON 形式が推奨されています
  • JSON スキーマにより IDE のサポートが向上します
  • JSONC ではコメントを使用できます
vite.config.ts(完全な例)
import { defineConfig } from 'vite'
import { cloudflare } from '@cloudflare/vite-plugin'

export default defineConfig({
  plugins: [
    cloudflare({
      // Persist state between HMR updates
      persist: true,
    }),
  ],

  // Optional: Configure server
  server: {
    port: 8787,
  },

  // Optional: Build optimizations
  build: {
    target: 'esnext',
    minify: true,
  },
})
tsconfig.json
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "ES2022",
    "lib": ["ES2022"],
    "moduleResolution": "bundler",
    "types": ["@cloudflare/workers-types/2023-07-01"],
    "resolveJsonModule": true,
    "allowJs": true,
    "checkJs": false,
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "isolatedModules": true,
    "noEmit": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules"]
}

API ルートのパターン

基本的な JSON レスポンス
app.get('/api/users', (c) => {
  return c.json({
    users: [
      { id: 1, name: 'Alice' },
      { id: 2, name: 'Bob' }
    ]
  })
})
リクエストボディを使った POST
app.post('/api/users', async (c) => {
  const body = await c.req.json()

  // Validate and process body
  return c.json({ success: true, data: body }, 201)
})
ルートパラメーター
app.get('/api/users/:id', (c) => {
  const id = c.req.param('id')
  return c.json({ id, name: 'User' })
})
クエリパラメーター
app.get('/api/search', (c) => {
  const query = c.req.query('q')
  return c.json({ query, results: [] })
})
エラー処理
app.get('/api/data', async (c) => {
  try {
    // Your logic here
    return c.json({ success: true })
  } catch (error) {
    return c.json({ error: error.message }, 500)
  }
})
バインディング(KV、D1、R2)の使用
type Bindings = {
  ASSETS: Fetcher
  MY_KV: KVNamespace
  DB: D1Database
  MY_BUCKET: R2Bucket
}

const app = new Hono<{ Bindings: Bindings }>()

app.get('/api/data', async (c) => {
  // KV
  const value = await c.env.MY_KV.get('key')

  // D1
  const result = await c.env.DB.prepare('SELECT * FROM users').all()

  // R2
  const object = await c.env.MY_BUCKET.get('file.txt')

  return c.json({ value, result, object })
})

静的アセットのベストプラクティス

ディレクトリ構成
public/
├── index.html          # Main entry point
├── styles.css          # Global styles
├── script.js           # Client-side JavaScript
├── favicon.ico         # Favicon
└── assets/             # Images, fonts, etc.
    ├── logo.png
    └── fonts/
SPA フォールバック

"not_found_handling": "single-page-application" の設定には、次の意味があります。

  • 不明なルートは index.html を返します
  • React Router、Vue Router などで役立ちます
  • ただし、API ルートには run_worker_first が必要です!
ルートの優先順位

"run_worker_first": ["/api/*"] の場合:

  1. /api/hello → Worker が処理します(JSON を返します)
  2. / → 静的アセットが index.html を配信します
  3. /styles.css → 静的アセットが styles.css を配信します
  4. /unknown → 静的アセットが index.html を配信します(SPA フォールバック)
静的アセットのキャッシュ

静的アセットはエッジで自動的にキャッシュされます。キャッシュを無効化するには:

<link rel="stylesheet" href="/styles.css?v=1.0.0">
<script src="/script.js?v=1.0.0"></script>

開発ワークフロー

ローカル開発
npm run dev
  • サーバーは http://localhost:8787 で実行されます
  • HMR が有効です(ファイルが変更されると自動的に再読み込みされます)
  • ローカルシミュレーションには Miniflare を使用します
  • すべてのバインディングをローカルで使用できます(KV、D1、R2)
API ルートのテスト
# Test GET endpoint
curl http://localhost:8787/api/hello

# Test POST endpoint
curl -X POST http://localhost:8787/api/echo \
  -H "Content-Type: application/json" \
  -d '{"test": "data"}'
型の生成
npm run cf-typegen

worker-configuration.d.ts を生成します。生成されるファイルには次の内容が含まれます。

  • バインディングの型(KV、D1、R2 など)
  • 環境変数の型
  • エディターでの自動補完
デプロイ
# Deploy to production
npm run deploy

# Deploy to specific environment
wrangler deploy --env staging

# Tail logs in production
wrangler tail

# Check deployment status
wrangler deployments list

セットアップの完全チェックリスト

  • npm create cloudflare@latest でプロジェクトを作成した
  • 依存関係をインストールした:[email protected]、@cloudflare/[email protected]
  • wrangler.jsonc を作成し、次の内容を設定した:
    • account_id に Cloudflare アカウントを設定した
    • assets.directory が ./public/ を指すように設定した
    • assets.run_worker_first に /api/* を含めた
    • compatibility_date に直近の日付を設定した
  • @cloudflare/vite-plugin を使用して vite.config.ts を作成した
  • Hono アプリを含む src/index.ts を作成した
    • export default app を使用している({ fetch: app.fetch } ではありません)
    • ASSETS バインディングの型を含めている
    • フォールバックルートがある:app.all('*', (c) => c.env.ASSETS.fetch(c.req.raw))
  • 静的ファイルを含む public/ ディレクトリを作成した
  • npm run cf-typegen が正常に実行された
  • npm run dev がエラーなしで起動する
  • API ルートをブラウザー/curl でテストした
  • 静的アセットが正しく配信される
  • クラッシュせずに HMR が動作する
  • npm run deploy でデプロイできる状態になっている

高度なトピック

ミドルウェアの追加
import { Hono } from 'hono'
import { logger } from 'hono/logger'
import { cors } from 'hono/cors'

const app = new Hono<{ Bindings: Bindings }>()

// Global middleware
app.use('*', logger())
app.use('/api/*', cors())

// Route-specific middleware
app.use('/admin/*', async (c, next) => {
  // Auth check
  await next()
})
環境ごとの設定
// wrangler.jsonc
{
  "name": "my-worker",
  "env": {
    "staging": {
      "vars": { "ENV": "staging" }
    },
    "production": {
      "vars": { "ENV": "production" }
    }
  }
}

デプロイ:wrangler deploy --env staging

カスタムエラーページ
app.onError((err, c) => {
  console.error(err)
  return c.json({ error: 'Internal Server Error' }, 500)
})

app.notFound((c) => {
  return c.json({ error: 'Not Found' }, 404)
})
Vitest を使用したテスト
npm install -D vitest @cloudflare/vitest-pool-workers

vitest.config.ts を作成します。

import { defineConfig } from 'vitest/config'

export default defineConfig({
  test: {
    poolOptions: {
      workers: {
        wrangler: { configPath: './wrangler.jsonc' },
      },
    },
  },
})

テストガイドの全編については、reference/testing.md を参照してください。


ファイルテンプレート

すべてのテンプレートは templates/ ディレクトリにあります。

  • wrangler.jsonc - Worker の完全な設定
  • vite.config.ts - Vite と Cloudflare プラグインのセットアップ
  • package.json - 依存関係とスクリプト
  • tsconfig.json - TypeScript の設定
  • src/index.ts - API ルートを含む Hono アプリ
  • public/index.html - 静的フロントエンドの例
  • public/styles.css - スタイル設定の例
  • public/script.js - API テスト関数

これらのファイルをプロジェクトにコピーし、必要に応じてカスタマイズしてください。


リファレンスドキュメント

詳しくは、次のドキュメントを参照してください。

  • architecture.md - エクスポートパターン、ルーティング、静的アセットの詳細
  • common-issues.md - 6 つの問題すべてと詳細なトラブルシューティング
  • deployment.md - Wrangler コマンド、CI/CD パターン、本番環境でのヒント

公式ドキュメント


依存関係(2025-10-20 に最新を確認)

{
  "dependencies": {
    "hono": "^4.10.1"
  },
  "devDependencies": {
    "@cloudflare/vite-plugin": "^1.13.13",
    "@cloudflare/workers-types": "^4.20251011.0",
    "vite": "^7.0.0",
    "wrangler": "^4.43.0",
    "typescript": "^5.9.0"
  }
}

本番環境での実例

このスキルは、cloudflare-worker-base-test プロジェクトに基づいています。

このスキルのすべてのパターンは、本番環境で検証済みです。


ご質問や問題がありますか?

  1. まず reference/common-issues.md を確認してください
  2. 4ステップのセットアップ手順をすべて確認してください
  3. export default app を使用していることを確認してください({ fetch: app.fetch } ではありません)
  4. run_worker_first が設定されていることを確認してください
  5. 公式ドキュメントを確認してください:https://developers.cloudflare.com/workers/

コメント