React Router v7 + Hono + bun でモノレポ構成の初期構築
この記事は?
この記事では、bun
の workspaces
機能を利用してモノレポ構成を構築し、バックエンドに Hono、フロントエンドに React Router v7を採用した場合の初期設定手順です。
バックエンドとフロントエンド間の通信には Hono の RPC (Remote Procedure Call) 機能を利用し、型安全な API コールを実現します。
deploy先として、Cloudflare Workersを想定しています。
インストール
プロジェクトのセットアップを行います。
1. 作業ディレクトリの作成とGit初期化
mkdir sample-app
cd sample-app
git init
2. .gitignore の作成
node_modules
を無視するように設定します。
node_modules
3. ワークスペース用ディレクトリの作成
モノレポの各アプリケーション(今回はバックエンドとフロントエンド)を配置するディレクトリを作成します。
mkdir apps
4. Bunのバージョンの確認(参考)
この記事の手順は以下のバージョンで確認しました。
node -v
# v22.2.0
bun -v
# 1.1.42
※Bunがインストールされていない場合は、Bun公式サイト の手順に従ってインストールしてください。
5. ルート package.json の作成
モノレポのルートに package.json
を作成し、workspaces
を設定します。"private": true
は、ルートパッケージ自体が公開されることを防ぐためのお約束です。
{
"name": "sample-app",
"version": "1.0.0",
"private": true,
"workspaces": [
"apps/*"
]
}
6. バックエンド (Hono) の作成
apps
ディレクトリに移動し、bun create
コマンドで Hono アプリケーションを作成します。
bun create hono@latest backend
templateはcloudflare-workersを選択します。
Which template do you want to use? › cloudflare-workers
Do you want to install project dependencies? › Yes
Which package manager do you want to use? › bun
7. フロントエンド (React Router) の作成
同様に apps
ディレクトリ内で、bunx create-react-router
コマンドを使って React Router アプリケーションを作成します。テンプレートには Cloudflare 向けのものを利用します。
bunx create-react-router@latest --template remix-run/react-router-templates/cloudflare frontend
Gitリポジトリはルートを利用するため No を選択します。
Initialize a new git repository? › No
Install dependencies with bun? › Yes
8. フロントエンドからバックエンドへの依存関係追加
フロントエンドからバックエンドの型定義などを参照するために、frontend
アプリケーションに backend
ワークスペースと hono
を追加します。
cd frontend
bun add hono backend
これで、基本的なファイル構造と依存関係のインストールが完了しました。
backend設定
次に、apps/backend
の設定を行います。
1. package.json の変更
package.json
を以下のように設定します。
{
"name": "backend", // 後で変更します
"type": "module",
"scripts": {
"dev": "wrangler dev",
"deploy": "wrangler deploy --minify"
},
"exports": {
".": "./src/index.ts"
},
"dependencies": {
"hono": "^4.7.5"
},
"devDependencies": {
"@cloudflare/workers-types": "^4.20250214.0",
"wrangler": "^4.4.0"
}
}
【重要】 後述する開発サーバー起動の問題のため、この name
は後で @sample-app/backend
に変更します。
2. src/index.ts の編集
API エンドポイントを作成します。今回はインストール時に用意されている /hello
という GET エンドポイントをそのまま利用します。また、ローカル開発時にフロントエンド (localhost:5173) からのアクセスを許可するために CORS ミドルウェアを設定します。
最後に、export type AppType = typeof route;
で Hono アプリケーションの型情報をエクスポートします。これが Hono RPC のキーとなります。
import { Hono } from "hono";
import { cors } from "hono/cors";
const app = new Hono();
// すべてのオリジンからのアクセスを許可(開発用)
app.use("*", cors({
origin: "*"
}));
// /hello エンドポイント
const route = app.get("/hello", (c) => {
return c.json({ message: "Hello Hono!" })
});
// Hono Client (RPC) のために型をエクスポート
export type AppType = typeof route;
export default app;
frontend設定
次に、apps/frontend
の設定を行います。
1. Hono Client の設定ファイル作成
バックエンド API と通信するためのクライアントを設定します。hono/client
の hc
を利用します。
apps/frontend/app/lib/client.ts
を作成します。
import type { AppType } from "backend"; // 後で変更します
import { hc } from "hono/client";
// TODO: URLはいったんローカルを固定で記述
export const client = hc<AppType>("http://localhost:8787"); // wrangler dev のデフォルトポート
ここで import type { AppType } from "backend";
と記述することで、backend
ワークスペースから型定義をインポートしています。これにより、client
はバックエンドのエンドポイント (/hello
) の型情報を認識し、型安全なコーディングが可能になります。
【重要】 後述する開発サーバー起動の問題のため、この import パスは後で @sample-app/backend
に変更します。
2. ルートコンポーネントの編集
React Router のルート (/
) に対応するコンポーネントを編集し、先ほど作成した Hono Client を使ってバックエンドからデータを取得・表示するようにします。React Router v7 では、loader
関数内でデータの取得を行います。
apps/frontend/app/routes/home.tsx
を以下のように編集します。
import type { Route } from "./+types/home";
import { client } from "~/lib/client"; // 作成した client をインポート
export function meta({}: Route.MetaArgs) {
return [
{ title: "New React Router App" },
{ name: "description", content: "Welcome to React Router!" },
];
}
// loader 関数でバックエンドからデータを取得
export async function loader({ context }: Route.LoaderArgs) {
// Hono Client を使って /hello エンドポイントを呼び出す (型安全!)
const res = await client.hello.$get();
const hello = await res.json();
return {
hello: hello.message // { hello: "Hello Hono!" } というオブジェクトを返す
};
}
// コンポーネントは loaderData からデータを受け取る
export default function Home({ loaderData }: Route.ComponentProps) {
return (
<div>
{/* loader から渡されたデータを表示 */}
{loaderData.hello}
</div>
)
}
client.hello.$get()
のように、型情報に基づいてメソッドチェーンで API を呼び出せるのが Hono Client の特徴です。
3. 開発サーバーの起動と問題解決
ルートディレクトリに戻り、bun run --filter
コマンドで両方の開発サーバーを同時に起動しようとします。
cd ../.. # ルートディレクトリへ移動
bun run --filter '*' dev
しかし、この時点では backend
の wrangler dev
は起動するものの、frontend
の開発サーバーが waiting for ...
のような状態で止まってしまい、正常に起動しませんでした。
調査したところ、以下の Issue が関連している可能性がありました。
https://github.com/oven-sh/bun/issues/10386
apps/backend/package.json
と apps/frontend/package.json
の name
フィールドを @<scope>/<package-name>
の形式(スコープ付きパッケージ名)に変更することで解決しました。
(根本的な原因は完全には特定できていませんが、スコープ付きパッケージ名にすることで Bun のワークスペース解決がうまくいく?)
{
"name": "@sample-app/backend", // 変更
// ... other fields
}
{
"name": "@sample-app/frontend", // 変更
// ... other fields
}
この変更に伴い、frontend
で backend
の型をインポートしている箇所のパスも変更する必要があります。
import type { AppType } from "@sample-app/backend"; // パスを変更
import { hc } from "hono/client";
// TODO: URLはいったんローカルを固定で記述
export const client = hc<AppType>("http://localhost:8787");
これらの変更後、再度 bun run --filter '*' dev
を実行すると、バックエンドとフロントエンドの両方の開発サーバーが正常に起動しました。
ブラウザで http://localhost:5173/
にアクセスすると、バックエンドから取得した "Hello Hono!" が表示されるはずです。
4. API URL の環境変数化 (TODO解消)
apps/frontend/app/lib/client.ts
にハードコードされていたバックエンドの URL (http://localhost:8787
) を環境変数から読み込むように修正します。
まず、.env
ファイルが Git 管理されないように、apps/frontendの .gitignore
に追記します。
.env # 追記
.env
ファイルを作成します。React Router (Vite) テンプレートでは、VITE_
プレフィックスが付いた環境変数がクライアントサイドコードに公開されます。
VITE_API_URL=http://localhost:8787
最後に、client.ts
を修正して環境変数を読み込みます。
import type { AppType } from "@sample-app/backend";
import { hc } from "hono/client";
// import.meta.env から環境変数を読み込む
export const client = hc<AppType>(import.meta.env.VITE_API_URL);
これで、開発環境では .env
ファイルの値が使われ、デプロイ時にはデプロイ環境の環境変数を設定することで、URL を切り替えられるようになります。
まとめ
この記事では、Bun Workspaces を利用してモノレポ環境を構築し、バックエンドに Hono、フロントエンドに React Router v7 をセットアップする初期手順を解説しました。
-
bun create
やbunx create-react-router
で各アプリケーションを初期化 - ルートの
package.json
でworkspaces
を設定 - Hono で API を作成し、
AppType
をエクスポート - React Router の
loader
で Hono Client (hc
) を使用し、型安全な API 通信を実装 - 開発サーバー同時起動時の問題と、スコープ付きパッケージ名への変更による対処法
- API エンドポイントの URL を環境変数で管理する方法
Hono の RPC 機能により、バックエンドとフロントエンド間の連携が非常にスムーズかつ安全に行えることが確認できました。Bun を活用したモノレポ構成の一例として参考になれば幸いです。
GitHub
本記事で作成したコードは以下のリポジトリで公開しています。
Discussion