docs/pages/deployment/single-origin/cloudflare.mdx 5.8 K raw
1
# Cloudflare
2
3
import { Button } from "vocs/components";
4
5
By using Cloudflare Workers you can host the `server` and the `client` in one deployment thanks to the built in [Static Assets Feature](https://hono.dev/docs/getting-started/cloudflare-workers#serve-static-files). With this approach everything will come through a single origin where any routes not covered by Hono will fallback to resolving via the static assets folder, which in our case is our React app.
6
7
## Prerequisites
8
9
This guide assumes you have a bhvr project set up. If not, start here:
10
11
```bash
12
bun create bhvr@latest my-app
13
cd my-app
14
```
15
16
<Button href='/getting-started'>Getting Started with bhvr</Button>
17
18
## Configuration
19
20
::::steps
21
22
### 1. Update Your Hono Server
23
24
Modify `server/src/index.ts` to have a new basepath of `/api`
25
26
```typescript
27
import { Hono } from "hono";
28
import { cors } from "hono/cors";
29
import type { ApiResponse } from "shared/dist";
30
31
const app = new Hono() // [!code --]
32
const app = new Hono().basePath("/api"); // [!code ++]
33
34
app.use(cors());
35
36
app.get("/", (c) => {
37
	return c.text("Hello Hono!");
38
});
39
40
app.get("/hello", async (c) => {
41
	const data: ApiResponse = {
42
		message: "Hello BHVR!",
43
		success: true,
44
	};
45
46
	return c.json(data, { status: 200 });
47
});
48
49
export default app;
50
```
51
52
### 2. Update Your React Client
53
54
Modify `client/src/App.tsx` to use a dynamic `SERVER_URL` based on dev / prod environment
55
56
```typescript
57
import { useState } from "react";
58
import beaver from "./assets/beaver.svg";
59
import { ApiResponse } from "shared";
60
import "./App.css";
61
62
const SERVER_URL = import.meta.env.VITE_SERVER_URL || "http://localhost:3000" // [!code --]
63
const SERVER_URL = import.meta.env.DEV ? "http://localhost:3000/api" : "/api";  // [!code ++]
64
65
function App() {
66
  const [data, setData] = useState<ApiResponse | undefined>();
67
68
  async function sendRequest() {
69
    try {
70
      const req = await fetch(`${SERVER_URL}/hello`);
71
      const res: ApiResponse = await req.json();
72
      setData(res);
73
    } catch (error) {
74
      console.log(error);
75
    }
76
  }
77
78
  return (
79
    <>
80
      <div>
81
        <a href='https://github.com/stevedylandev/bhvr' target='_blank'>
82
          <img src={beaver} className='logo' alt='beaver logo' />
83
        </a>
84
      </div>
85
      <h1>bhvr</h1>
86
      <h2>Bun + Hono + Vite + React</h2>
87
      <p>A typesafe fullstack monorepo</p>
88
      <div className='card'>
89
        <button onClick={sendRequest}>Call API</button>
90
        {data && (
91
          <pre className='response'>
92
            <code>
93
              Message: {data.message} <br />
94
              Success: {data.success.toString()}
95
            </code>
96
          </pre>
97
        )}
98
      </div>
99
      <p className='read-the-docs'>Click the beaver to learn more</p>
100
    </>
101
  );
102
}
103
104
export default App;
105
```
106
107
### 3. Setup Wrangler
108
109
Install `wrangler` and it's types at the root of your bhvr project
110
111
```bash [terminal]
112
bun add --dev wrangler @cloudflare/workers-types
113
```
114
115
Then create another file at the root of the project called `wrangler.jsonc` with the following content:
116
117
```jsonc
118
{
119
	"$schema": "./node_modules/wrangler/config-schema.json",
120
	"name": "bhvr-project", // Name of your project
121
	"main": "./server/dist/index.js", // Path to worker
122
	"compatibility_date": "2025-05-25",
123
	"assets": {
124
		"directory": "./client/dist", // Path to client build folder
125
		"not_found_handling": "single-page-application", // Handle SPA routing		
126
		"run_worker_first": ["/api/*"]
127
128
	},
129
	"compatibility_flags": ["nodejs_compat"] // Enable node for Vite path features
130
}
131
```
132
133
### 4. Add Deploy Script
134
135
Append a deploy script to your root `package.json` (alongside the existing bhvr scripts):
136
137
```json
138
{
139
  "scripts": {
140
  	"dev": "turbo dev",
141
  	"dev:client": "turbo dev --filter=client",
142
  	"dev:server": "turbo dev --filter=server",
143
  	"build": "turbo build",
144
  	"build:client": "turbo build --filter=client",
145
  	"build:server": "turbo build --filter=server",
146
  	"lint": "turbo lint",
147
  	"type-check": "turbo type-check",
148
  	"test": "turbo test",
149
  	"postinstall": "turbo build --filter=shared --filter=server",
150
  	"deploy": "turbo build && wrangler deploy --minify" // [!code ++]
151
	},
152
}
153
```
154
155
### 5. Deploy
156
157
Make sure you have logged into Cloudflare using Wrangler first
158
159
```bash [terminal]
160
bunx wrangler login
161
```
162
163
Then run the deployment script
164
165
```bash [terminal]
166
bun run deploy
167
```
168
169
::::
170
171
## Environment Variables
172
173
You can use environment variables just like you would with Hono + Cloudflare workers as described in the [Hono Docs](https://hono.dev/docs/getting-started/cloudflare-workers#bindings) for Bindings. Here is an example of what you might have in `server/src/index.ts`:
174
175
```typescript
176
import { Hono } from "hono";
177
import { cors } from "hono/cors";
178
import type { ApiResponse } from "shared/dist";
179
180
type Bindings = {
181
	SECRET: string;
182
};
183
184
const app = new Hono<{ Bindings: Bindings }>().basePath("/api");
185
186
app.use(cors());
187
188
app.get("/", (c) => {
189
	return c.text("Hello Hono!");
190
});
191
192
app.get("/hello", async (c) => {
193
	const data: ApiResponse = {
194
		message: `Hello BHVR! (this is the secret: ${c.env.SECRET}`,
195
		success: true,
196
	};
197
198
	return c.json(data, { status: 200 });
199
});
200
201
export default app;
202
```
203
204
To add the secret in dev you would create a `.dev.vars` file in `server` with the variable
205
206
```
207
SECRET=hotdog
208
```
209
210
:::warning
211
Make sure to add .dev.vars to your `.gitignore`!
212
:::
213
214
To add it in production, you can either add it through the Cloudflare dashboard or through Wrangler:
215
216
```bash [terminal]
217
bunx wrangler secret put SECRET
218
# Will prompt you to enter the secret
219
```
220
221
For client side variables you can simply include them in a local `.env.local` file in the root of the `client` package, and make sure to use the `VITE_` prefix for them. When you build they will automatically be included in the `dist` bundle.
222
223
:::warning
224
Make sure only public variables are in the client!
225
:::
226
227
228
## More Resources
229
230
<Button href='/getting-started'>Getting Started with bhvr</Button>
231
<Button href='https://hono.dev'>Hono Docs</Button>