ViteとhonoでCloudflare WorkersでWebページとAPIを作成する
こんばんは、情報システム室の夏目です。
個人的にWebアプリを作成する際、Cloudflare Pagesを使っていました。
久しぶりに作成しようとしたところ去年の4月に「新規開発はWorkersから始めるべき」という方針が出されていたことを知りました。
今回はCloudflate PagesとFunctionsの代わりにWorkersを使ってViteでReactのWebアプリの初期セットアップをしようと思います。
1. create-viteでプロジェクトの作成
$ npm create vite@latest
> npx
> "create-vite"
│
◇ Project name:
│ trial-cloudflare-worker
│
◇ Select a framework:
│ React
│
◇ Select a variant:
│ TypeScript + React Compiler
│
◇ Which linter to use?
│ Oxlint
│
◇ Install with npm and start now?
│ No
│
◇ Scaffolding project in /xxxxx/trial-cloudflare-worker...
│
└ Done. Now run:
cd trial-cloudflare-worker
npm install
npm run dev
$ cd trial-cloudflare-worker
$ npm install
ViteでReactのプロジェクトを作成して、依存ライブラリのインストールを行います。
$ eza -T
.
├── index.html
├── package.json
├── public
│ ├── favicon.svg
│ └── icons.svg
├── README.md
├── src
│ ├── App.css
│ ├── App.tsx
│ ├── assets
│ │ ├── hero.png
│ │ ├── react.svg
│ │ └── vite.svg
│ ├── index.css
│ └── main.tsx
├── tsconfig.app.json
├── tsconfig.json
├── tsconfig.node.json
└── vite.config.ts
今のファイル構成はこんな感じです。
2. Cloudflare Workers用の依存関係の追加
$ npm install -D wrangler @cloudflare/vite-plugin
Cloudflare Workers用の依存関係を追加します。
@cloudflare/vite-plugin を使うことでCloudflare Workersに近い環境でローカル実行されるようになったり、Worker用のコードも vite buildでビルドしてくれるようになります。
これにより wrangler deploy が vite build の出力を認識し、追加のバンドル処理なしでデプロイできるようになります。
3. vite.config.ts にCloudflare pluginを追加
import { defineConfig } from 'vite'
import react, { reactCompilerPreset } from '@vitejs/plugin-react'
import babel from '@rolldown/plugin-babel'
import { cloudflare } from '@cloudflare/vite-plugin'
// https://vite.dev/config/
export default defineConfig({
plugins: [
react(),
babel({ presets: [reactCompilerPreset()] }),
cloudflare(),
],
})
pluginsに cloudflare() を追加するだけです。
4. Cloudflare Workersの設定ファイルを作成する
{
"$schema": "./node_modules/wrangler/config-schema.json",
"name": "trial-cloudflare-worker",
// Set this to today's date
"compatibility_date": "2026-07-16",
"assets": {
"not_found_handling": "single-page-application"
}
}
"not_found_handling": "single-page-application" を設定することでファイルが見つからないリクエストはすべてindex.htmlにルーティングされるようになります。
@cloudflare/vite-plugin を使用しているとViteのデフォルトの動作の代わりに使用され、ルーティング設定が開発時と本番環境の両方で同じように動作します。
ここまで設定すれば、静的ファイルだけで構成されるSPAならデプロイ可能です。
Githubのリポジトリを繋げたり、wranglerコマンドを使用してデプロイすればSPAとして公開されます。
今回はCloudflare Pages Functions部分もWorkersでやりたいので、Workerの設定を進めていきます。
5. Workerの最小構成を作る
5-1. package.jsonのscriptsに追記
{
"scripts": {
"cf-typegen": "wrangler types",
"typecheck": "npm run cf-typegen && tsc -b",
"build": "npm run typecheck && vite build",
"deploy": "npm run build && wrangler deploy"
}
}
package.jsonのscriptsに上記の4つを追加します。
cf-typegen- wrangler.jsoncからCloudflare Workers用の型定義ファイル
worker-configuration.d.tsというファイルを生成します @cloudflare/workers-typesというnpm packageで代替ができますが、Workerに設定しているバインディング(KVとかR2とか)やVariable, Secretも反映したものを生成してくれます
- wrangler.jsoncからCloudflare Workers用の型定義ファイル
typecheck- Worker用の型定義ファイルを生成し、TypeScriptの型チェックを行います
buildvite buildでフロントエンドとワーカー用のビルドを行います
deploy- Cloudflare Workersにデプロイします
- 手動デプロイする場合は使用します
5-2. TypeScriptのビルド設定をする
{
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.worker.tsbuildinfo",
"target": "ES2022",
"lib": ["ES2022"],
"module": "esnext",
"moduleResolution": "bundler",
"types": ["./worker-configuration.d.ts"],
"noEmit": true,
"strict": true,
"skipLibCheck": true,
"isolatedModules": true,
"verbatimModuleSyntax": true,
"moduleDetection": "force"
},
"include": ["worker", "worker-configuration.d.ts"]
}
Cloudflare Worker用のtsconfigファイルを作成します。
設定値の大部分をtsconfig.node.jsonに頼って最小限だけ書くこともできるのですが、個人的に意図しない設定が含まれていたので新規に書き下ろしました (AIに全力で頼りましたが)。
{
"files": [],
"references": [
{ "path": "./tsconfig.app.json" },
{ "path": "./tsconfig.node.json" },
{ "path": "./tsconfig.worker.json" }
]
}
tsconfig.jsonを編集して、tsconfig.worker.jsonも読み込むように設定します。
5-3. Worker用のtsファイルを書き、wrangler.jsoncを更新する
$ mkdir worker
Worker用のtsファイルを置くディレクトリを作成します。
export default {
async fetch(request, env, ctx): Promise<Response> {
const url = new URL(request.url);
if (url.pathname.startsWith("/api/")) {
return Response.json({
ok: true,
path: url.pathname,
});
}
return new Response(null, { status: 404 });
},
} satisfies ExportedHandler<Env>;
こちらはドキュメントにあったサンプルを参考に書いたものです。
とりあえず、最小構成のコードとしてはこれでいいでしょう。
{
"main": "./worker/index.ts",
"assets": {
"not_found_handling": "single-page-application",
"run_worker_first": [
"/api/*"
]
}
}
wrangler.jsoncに上記内容を追記します。
Worker用のtsファイルを main で明記します。
run_worker_first を設定することで、明示的にWorkerを動かしたいパスを定義できます。
これでWorkerを動かすこともできるようになりました。
デプロイすればWorkerもデプロイされます。
5. honoでWorkerを書く
今の worker/index.ts を見ると、ルーティングを自分で行う必要があるのがわかります。
さすがにそのままでは面倒です。
なので今回はhonoを使ってルーティングを行います。
$ npm install hono
まずhonoをインストールします。
import { Hono } from "hono";
type AppEnv = {
Bindings: Env
};
const app = new Hono<AppEnv>();
app.get("/api/*", (c) => {
return c.json({
ok: true,
path: new URL(c.req.url).pathname,
});
});
app.notFound((c) => {
return c.body(null, 404);
});
export default app;
今のコードをhonoで書き直すとこうなります。
ルーティングをhonoに任せられるので、APIを増やす際にも書きやすくなりました。
まとめ
以上、自分がCloudflare PagesからCloudflare Workersに移行する際に行ったことでした。
何かのお役に立てれば幸いです。







