cfコマンドを使ってViteで作成したReactアプリをCloudflare Workersにデプロイする

cfコマンドを使ってViteで作成したReactアプリをCloudflare Workersにデプロイする

Cloudflare Workersの新しいcfコマンドが登場したので、Viteで作成したReactアプリをデプロイしてみました。ベータ版ツールの使い方から実際のデプロイまで、全ステップを紹介します。
2026.10.06

こんばんは、情報システム室の夏目です。

最近個人開発でCloudflare Workersをよく使っています。

先日Cloudflareが新しいCLI "cf" コマンドをオープンベータでリリースしました。

今回はViteで作成したReactアプリをcfコマンドでCloudflare Workersにデプロイしようと思います。

1. Viteでプロジェクトを作成する

Viteでプロジェクトを作成します。
今回はプロジェクト名を trial-cf-react-worker とします。

選択肢は以下のようの選択しました。

  • Select a framework: React
  • Select a variant: TypeScript + React Compiler
  • Which linter to use?: Oxlint
  • Install 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 を作成します。

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も読み込むように設定します。

tsconfig.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 を使用するように設定します。

vite.config.ts
+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を作成します。

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のコードを修正して、動いていることを確認できるようにします。

src/mian.tsx
 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>,
 );
src/App.tsx
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を編集して複数ページある状態にします。

src/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 もベータ版を使う必要があるので、早くベータを抜けてほしいところです。

何かのお役に立てたら幸いです。

参考

この記事をシェアする

関連記事