
cfコマンドを使ってViteで作成したReactアプリをCloudflare Workersにデプロイする
こんばんは、情報システム室の夏目です。
最近個人開発でCloudflare Workersをよく使っています。
先日Cloudflareが新しいCLI "cf" コマンドをオープンベータでリリースしました。
今回はViteで作成したReactアプリをcfコマンドでCloudflare Workersにデプロイしようと思います。
1. Viteでプロジェクトを作成する
Viteでプロジェクトを作成します。
今回はプロジェクト名を trial-cf-react-worker とします。
選択肢は以下のようの選択しました。
Select a framework:ReactSelect a variant:TypeScript + React CompilerWhich linter to use?:OxlintInstall with npm and start now?:No
$ npm create vite@latest trial-cf-react-worker
2. cfコマンドとViteプラグインをインストールする
Cloudflare Workersにデプロイするためにcfコマンドと @cloudflare/vite-plugin をインストールします。
$ cd trial-cf-react-worker
$ npm install -D cf @cloudflare/vite-plugin@beta
現在cfコマンドでデプロイするためには @cloudflare/vite-plugin はベータ版を使用する必要があります。
検証中に安定版のv1系を使おうとしたところ、v2 betaが必要だとエラーが出ました。
$ npx cf deploy @cloudflare/vite-plugin@1.62.5 is installed, but it is not compatible with cf's local runtime. cf requires @cloudflare/vite-plugin v2 beta for cf dev, cf build, cf deploy, and cf previews deploy. Try: npm install --save-dev @cloudflare/vite-plugin@beta@cloudflare/vite-pluginのv1系でデプロイしようとしたときのエラー
3. Worker用のコード実装や設定を作成する
Worker用のコード実装や設定をしていきます。
リクエストが来ると {"ok": true, "message": "Hello"} と返すWorkerの実装をします。
最初はWorker用のtsconfigファイル tsconfig.worker.json を作成します。
{
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.worker.tsbuildinfo",
"target": "es2024",
"lib": ["es2024"],
"module": "preserve",
"moduleResolution": "bundler",
"types": [],
"strict": true,
"noEmit": true,
"allowImportingTsExtensions": true,
"isolatedModules": true,
"verbatimModuleSyntax": true,
"skipLibCheck": true
},
"include": ["worker", "cloudflare.config.ts", ".cloudflare/types"]
}
これは cf init でWorkerのプロジェクトを作成したときのtsconfig.jsonを元に作成しました。
大事なのは "include": ["worker", "cloudflare.config.ts", ".cloudflare/types"] です。
worker- 今回Worker用のコードを置く場所
cf initで作成したときにはsrcとなっているが、Reactのコードとバッティングするのでworkerとした
cloudflare.config.ts- cfコマンドを作成する場合のWorkerの設定ファイル
.cloudflare/types- cfコマンドが型ファイルを生成するときに配置される先
次にtsconfig.jsonでtsconfig.worker.jsonも読み込むように設定します。
{
"files": [],
- "references": [{ "path": "./tsconfig.app.json" }, { "path": "./tsconfig.node.json" }]
+ "references": [
+ { "path": "./tsconfig.app.json" },
+ { "path": "./tsconfig.node.json" },
+ { "path": "./tsconfig.worker.json" }
+ ]
}
vite.config.tsで @cloudflare/vite-plugin を使用するように設定します。
+import { cloudflare } from "@cloudflare/vite-plugin";
import babel from "@rolldown/plugin-babel";
import react, { reactCompilerPreset } from "@vitejs/plugin-react";
import { defineConfig } from "vite";
// https://vite.dev/config/
export default defineConfig({
- plugins: [react(), babel({ presets: [reactCompilerPreset()] })],
+ plugins: [react(), babel({ presets: [reactCompilerPreset()] }), cloudflare()],
});
参考にした記事では cloudflare({ experimental: { newConfig: true } }) が必要とあったのですが、必要ないことがわかりました。
(v2 betaのvite-pluginではcloudflare.config.tsをデフォルトで見るようになっている模様)
次に、cloudflare.config.tsを作成します。
import { defineConfig } from "cf/config";
import * as entrypoint from "./worker/index.ts" with { type: "cf-worker" };
export default defineConfig({
worker: {
name: "trial-cf-react-worker",
compatibilityDate: "2026-10-06",
entrypoint,
assets: {
notFoundHandling: "single-page-application",
runWorkerFirst: ["/api/*"],
},
},
});
ここも cf init で作成されるcloudflare.config.tsを参考に、SPA用の設定を追加しています。
設定ファイルであるcloudflare.config.tsを作成したので型ファイルを生成します。
$ npx cf workers types
🍊☁️ cf · v1.0.0-beta.12
─────────────────────────
{
"path": ".cloudflare/types/index.d.ts"
}
最後にWorker用のindex.tsを作成します。
export default {
fetch() {
return Response.json({ ok: true, message: "Hello" });
},
} satisfies ExportedHandler;
4. Reactのコードを修正する
Reactのコードを修正して、動いていることを確認できるようにします。
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
-import "./index.css";
import App from "./App.tsx";
createRoot(document.getElementById("root")!).render(
<StrictMode>
<App />
</StrictMode>,
);
export default function App() {
async function call() {
const resp = await fetch("/api/hello");
alert(await resp.text());
}
return (
<>
<h1>Trial Cf React Worker</h1>
<hr />
<p>
<button onClick={call}>Call</button>
</p>
</>
);
}
5. デプロイする
cfコマンドでデプロイをします。
$ npx cf deploy
...(中略)...
│ Uploaded trial-cf-react-worker (4.38 sec)
│ Deployed trial-cf-react-worker triggers (0.71 sec)
│ https://trial-cf-react-worker.luciferous.workers.dev
│ Current Version ID: 2d0cf0a5-3f3f-48f0-99d2-3a38c26cde8a
│
◆ Deploy complete
6. ブラウザで開いてみる
生成されたURLをブラウザで開いてみます。
またCallボタンをクリックして、Workerも動くかを確認します。

7. React Routerを入れてSPAがきちんと動くかも見る
SPAとして複数ページのときもきちんと動くかどうかを、React Routerを入れて確認してみます。
$ npm install react-router
main.tsxを編集して複数ページある状態にします。
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import { createBrowserRouter, Link } from "react-router";
import { RouterProvider } from "react-router/dom";
const router = createBrowserRouter([
{
path: "/",
element: (
<>
<h1>Home</h1>
<hr />
<p>
<Link to="/page-1">Page 1</Link>
</p>
<p>
<Link to="/page-2">Page 2</Link>
</p>
</>
),
},
{
path: "/page-1",
element: (
<>
<h1>Page 1</h1>
<hr />
<p>
<Link to="/">Home</Link>
</p>
</>
),
},
{
path: "/page-2",
element: (
<>
<h1>Page 2</h1>
<hr />
<p>
<Link to="/">Home</Link>
</p>
</>
),
},
]);
createRoot(document.getElementById("root")!).render(
<StrictMode>
<RouterProvider router={router} />
</StrictMode>,
);
cfコマンドでデプロイします。
$ npx cf deploy
再度ブラウザでアクセスしてみます。



問題なく表示されました。
ページ遷移だけではなく、Page 1やPage 2のURLでダイレクトにアクセスしたときも問題なく表示されました。
まとめ
以上Viteで作成したReactアプリをcfコマンドでCloudflare Workersにデプロイする話でした。
cfコマンドも @cloudflare/vite-plugin もベータ版を使う必要があるので、早くベータを抜けてほしいところです。
何かのお役に立てたら幸いです。




