🍏

React Router v7 middleware を Cloudflare Workers で使う (v7.9安定化版)

に公開

React Router v7 のミドルウェアを Cloudflare Workers で使う方法です。Cloudflare 独特のコンテキスト (cloudflare.ctxcloudflare.env) を参照させるサンプルコードにもなっています。

すでに React Router v7 のミドルウェアを利用した事例は色々な方が書いてくださっているのですが、v7.8.0 での破壊的変更がありましたので、備忘録として纏めました。

破壊的変更に関連するのは「2. Context Providerの定義」のセクションです。

補足

以下のサンプルでは Cloudflare の環境変数やバインディングへアクセスする際に、Cloudflare Context を使う形になっていますが、Workers の env および waitUntil はコンテキストを経由せずとも "cloudflare:workers" から直接インポート可能です。RouteContextProvider` 経由で使うよりも楽だと思います。

https://developers.cloudflare.com/changelog/2025-08-08-add-waituntil-cloudflare-workers/

middleware 導入手順

1. 設定の追加 (react-router.config.ts)

export default {
  ssr: true,
  future: {
    unstable_viteEnvironmentApi: true,
+   v8_middleware: true,
  },
} satisfies Config;

v8_middleware: trueを設定することで、ミドルウェア機能が使用可能になります。

2. Context Providerの定義 (workers/app.ts)

- import { createRequestHandler } from "react-router";
+ import { createRequestHandler, createContext, RouterContextProvider } from "react-router";

- declare module "react-router" {
-   export interface AppLoadContext {
-     cloudflare: {
-       env: Env;
-       ctx: ExecutionContext;
-     };
-   }
- }
+ export const CloudflareContext = createContext<{
+   cloudflare: {
+     env: Env;
+     ctx: ExecutionContext;
+   };
+ }>();

export default {
  async fetch(request, env, ctx) {
-   return requestHandler(request, {
+   const context = new RouterContextProvider();
+   context.set(CloudflareContext, {
      cloudflare: { env, ctx },
    });
+   return requestHandler(request, context);
  },
} satisfies ExportedHandler<Env>;

従来の AppLoadContext からRouterContextProvider に変更し、Cloudflareの環境情報を Context として設定します。

3. ルートでのMiddleware使用 (app/routes/home.tsx)

import type { Route } from "./+types/home";
import { Welcome } from "../welcome/welcome";
+ import { CloudflareContext } from "workers/app";
+ import { createContext } from "react-router";

+ const UserContext = createContext<{ user: { id: string } }>();

+ const authMiddleware: Route.MiddlewareFunction = async ({ request, context }) => {
+   const user = { id: "12345" };
+   context.set(UserContext, { user });
+ }

+ export const middleware: Route.MiddlewareFunction[] = [authMiddleware];

export function loader({ context }: Route.LoaderArgs) {
- return { message: context.cloudflare.env.VALUE_FROM_CLOUDFLARE };
+ const cfContext = context.get(CloudflareContext);
+ const { user } = context.get(UserContext);
+ console.log(`User ID: ${user.id}`)
+ return { message: cfContext.cloudflare.env.VALUE_FROM_CLOUDFLARE };
}

ミドルウェアを使わない従来の場合は、Cloudflare のコンテキストは context.cloudflare として参照できましたが、ミドルウェアを利用する場合は、上記のように context.get() を組み合わせて参照が必要です。

また上記ではサンプルとして UserContext を定義し、loader() の中で利用するパターンも示しています。

以上の内容は以下のリポジトリにおいておきます。

https://github.com/yuheitomi/example-react-router-middleware-cloudflare

参考

GitHubで編集を提案

Discussion