This commit is contained in:
@@ -1,19 +1,19 @@
|
||||
# bknd starter: Cloudflare Vite Hybrid
|
||||
A fullstack React + Vite application with bknd integration, showcasing **hybrid mode** and Cloudflare Workers deployment.
|
||||
# userbase starter: Cloudflare Vite Hybrid
|
||||
A fullstack React + Vite application with userbase integration, showcasing **hybrid mode** and Cloudflare Workers deployment.
|
||||
|
||||
## Key Features
|
||||
|
||||
This example demonstrates several advanced bknd features:
|
||||
This example demonstrates several advanced userbase features:
|
||||
|
||||
### 🔄 Hybrid Mode
|
||||
Configure your backend **visually in development** using the Admin UI, then automatically switch to **code-only mode in production** for maximum performance. Changes made in the Admin UI are automatically synced to `bknd-config.json` and type definitions are generated in `bknd-types.d.ts`.
|
||||
Configure your backend **visually in development** using the Admin UI, then automatically switch to **code-only mode in production** for maximum performance. Changes made in the Admin UI are automatically synced to `userbase-config.json` and type definitions are generated in `userbase-types.d.ts`.
|
||||
|
||||
### 📁 Filesystem Access with Vite Plugin
|
||||
Cloudflare's Vite plugin uses `unenv` which disables Node.js APIs like `fs`. This example uses bknd's `devFsVitePlugin` and `devFsWrite` to provide filesystem access during development, enabling automatic syncing of types and configuration.
|
||||
Cloudflare's Vite plugin uses `unenv` which disables Node.js APIs like `fs`. This example uses userbase's `devFsVitePlugin` and `devFsWrite` to provide filesystem access during development, enabling automatic syncing of types and configuration.
|
||||
|
||||
### ⚡ Split Configuration Pattern
|
||||
- **`config.ts`**: Shared configuration that can be safely imported in your worker
|
||||
- **`bknd.config.ts`**: Wraps the configuration with `withPlatformProxy` for CLI usage with Cloudflare bindings (should NOT be imported in your worker)
|
||||
- **`userbase.config.ts`**: Wraps the configuration with `withPlatformProxy` for CLI usage with Cloudflare bindings (should NOT be imported in your worker)
|
||||
|
||||
This pattern prevents bundling `wrangler` into your worker while still allowing CLI access to Cloudflare resources.
|
||||
|
||||
@@ -27,15 +27,15 @@ Inside of your project, you'll see the following folders and files:
|
||||
│ ├── app/ # React frontend application
|
||||
│ │ ├── App.tsx
|
||||
│ │ ├── routes/
|
||||
│ │ │ ├── admin.tsx # bknd Admin UI route
|
||||
│ │ │ ├── admin.tsx # userbase Admin UI route
|
||||
│ │ │ └── home.tsx # Example frontend route
|
||||
│ │ └── main.tsx
|
||||
│ └── worker/
|
||||
│ └── index.ts # Cloudflare Worker entry
|
||||
├── config.ts # Shared bknd configuration (hybrid mode)
|
||||
├── bknd.config.ts # CLI configuration with platform proxy
|
||||
├── bknd-config.json # Auto-generated production config
|
||||
├── bknd-types.d.ts # Auto-generated TypeScript types
|
||||
├── config.ts # Shared userbase configuration (hybrid mode)
|
||||
├── userbase.config.ts # CLI configuration with platform proxy
|
||||
├── userbase-config.json # Auto-generated production config
|
||||
├── userbase-types.d.ts # Auto-generated TypeScript types
|
||||
├── .env.example # Auto-generated secrets template
|
||||
├── vite.config.ts # Includes devFsVitePlugin
|
||||
├── package.json
|
||||
@@ -51,8 +51,8 @@ Inside of your project, you'll see the following folders and files:
|
||||
|
||||
## Admin UI & frontend
|
||||
|
||||
- `/admin` mounts `<Admin />` from `bknd/ui` with `withProvider={{ user }}` so it respects the authenticated user returned by `useAuth`.
|
||||
- `/` showcases `useEntityQuery("todos")`, mutation helpers, and authentication state — demonstrating how the generated client types (`bknd-types.d.ts`) flow into the React code.
|
||||
- `/admin` mounts `<Admin />` from `userbase/ui` with `withProvider={{ user }}` so it respects the authenticated user returned by `useAuth`.
|
||||
- `/` showcases `useEntityQuery("todos")`, mutation helpers, and authentication state — demonstrating how the generated client types (`userbase-types.d.ts`) flow into the React code.
|
||||
|
||||
|
||||
## Configuration Files
|
||||
@@ -60,25 +60,25 @@ Inside of your project, you'll see the following folders and files:
|
||||
### `config.ts`
|
||||
The main configuration file that uses the `hybrid()` mode helper:
|
||||
|
||||
- Loads the generated config via an ESM `reader` (importing `./bknd-config.json`).
|
||||
- Loads the generated config via an ESM `reader` (importing `./userbase-config.json`).
|
||||
- Uses `devFsWrite` as the `writer` so the CLI/plugin can persist files even though Node's `fs` API is unavailable in Miniflare.
|
||||
- Sets `typesFilePath`, `configFilePath`, and `syncSecrets` (writes `.env.example`) so config, types, and secret placeholders stay aligned.
|
||||
- Seeds example data/users in `options.seed` when the database is empty.
|
||||
- Disables the built-in admin controller because the React app renders `/admin` via `bknd/ui`.
|
||||
- Disables the built-in admin controller because the React app renders `/admin` via `userbase/ui`.
|
||||
|
||||
|
||||
```typescript
|
||||
import { hybrid } from "bknd/modes";
|
||||
import { devFsWrite, type CloudflareBkndConfig } from "bknd/adapter/cloudflare";
|
||||
import { hybrid } from "userbase/modes";
|
||||
import { devFsWrite, type CloudflareUserbaseConfig } from "userbase/adapter/cloudflare";
|
||||
|
||||
export default hybrid<CloudflareBkndConfig>({
|
||||
export default hybrid<CloudflareUserbaseConfig>({
|
||||
// Special reader for Cloudflare Workers (no Node.js fs)
|
||||
reader: async () => (await import("./bknd-config.json")).default,
|
||||
reader: async () => (await import("./userbase-config.json")).default,
|
||||
// devFsWrite enables file writing via Vite plugin
|
||||
writer: devFsWrite,
|
||||
// Auto-sync these files in development
|
||||
typesFilePath: "./bknd-types.d.ts",
|
||||
configFilePath: "./bknd-config.json",
|
||||
typesFilePath: "./userbase-types.d.ts",
|
||||
configFilePath: "./userbase-config.json",
|
||||
syncSecrets: {
|
||||
enabled: true,
|
||||
outFile: ".env.example",
|
||||
@@ -93,11 +93,11 @@ export default hybrid<CloudflareBkndConfig>({
|
||||
});
|
||||
```
|
||||
|
||||
### `bknd.config.ts`
|
||||
### `userbase.config.ts`
|
||||
Wraps the configuration for CLI usage with Cloudflare bindings:
|
||||
|
||||
```typescript
|
||||
import { withPlatformProxy } from "bknd/adapter/cloudflare/proxy";
|
||||
import { withPlatformProxy } from "userbase/adapter/cloudflare/proxy";
|
||||
import config from "./config.ts";
|
||||
|
||||
export default withPlatformProxy(config);
|
||||
@@ -107,7 +107,7 @@ export default withPlatformProxy(config);
|
||||
Includes the `devFsVitePlugin` for filesystem access:
|
||||
|
||||
```typescript
|
||||
import { devFsVitePlugin } from "bknd/adapter/cloudflare";
|
||||
import { devFsVitePlugin } from "userbase/adapter/cloudflare";
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
@@ -129,8 +129,8 @@ All commands are run from the root of the project, from a terminal:
|
||||
| `npm run build` | Builds the application for production |
|
||||
| `npm run preview` | Builds and previews the production build locally |
|
||||
| `npm run deploy` | Builds, syncs the schema and deploys to Cloudflare Workers|
|
||||
| `npm run bknd` | Runs bknd CLI commands |
|
||||
| `npm run bknd:types` | Generates TypeScript types from your schema |
|
||||
| `npm run userbase` | Runs userbase CLI commands |
|
||||
| `npm run userbase:types` | Generates TypeScript types from your schema |
|
||||
| `npm run cf:types` | Generates Cloudflare Worker types from `wrangler.json` |
|
||||
| `npm run check` | Type checks and does a dry-run deployment |
|
||||
|
||||
@@ -153,17 +153,17 @@ All commands are run from the root of the project, from a terminal:
|
||||
- Define permissions
|
||||
|
||||
4. **Watch for auto-generated files:**
|
||||
- `bknd-config.json` - Production configuration
|
||||
- `bknd-types.d.ts` - TypeScript types
|
||||
- `userbase-config.json` - Production configuration
|
||||
- `userbase-types.d.ts` - TypeScript types
|
||||
- `.env.example` - Required secrets
|
||||
|
||||
5. **Use the CLI** for manual operations:
|
||||
```sh
|
||||
# Generate types manually
|
||||
npm run bknd:types
|
||||
npm run userbase:types
|
||||
|
||||
# Sync the production database schema (only safe operations are applied)
|
||||
CLOUDFLARE_ENV=production npm run bknd -- sync --force
|
||||
CLOUDFLARE_ENV=production npm run userbase -- sync --force
|
||||
```
|
||||
|
||||
## Before you deploy
|
||||
@@ -200,8 +200,8 @@ This will:
|
||||
2. Build the Vite application
|
||||
3. Deploy to Cloudflare Workers using Wrangler
|
||||
|
||||
In production, bknd will:
|
||||
- Use the configuration from `bknd-config.json` (read-only)
|
||||
In production, userbase will:
|
||||
- Use the configuration from `userbase-config.json` (read-only)
|
||||
- Skip config validation for better performance
|
||||
- Expect secrets to be provided via environment variables
|
||||
|
||||
@@ -221,15 +221,15 @@ Check `.env.example` for all required secrets after running the app in developme
|
||||
```mermaid
|
||||
graph LR
|
||||
A[Development] -->|Visual Config| B[Admin UI]
|
||||
B -->|Auto-sync| C[bknd-config.json]
|
||||
B -->|Auto-sync| D[bknd-types.d.ts]
|
||||
B -->|Auto-sync| C[userbase-config.json]
|
||||
B -->|Auto-sync| D[userbase-types.d.ts]
|
||||
C -->|Deploy| E[Production]
|
||||
E -->|Read-only| F[Code-only Mode]
|
||||
```
|
||||
|
||||
1. **In Development:** `mode: "db"` - Configuration stored in database, editable via Admin UI
|
||||
2. **Auto-sync:** Changes automatically written to `bknd-config.json` and types to `bknd-types.d.ts`
|
||||
3. **In Production:** `mode: "code"` - Configuration read from `bknd-config.json`, no database overhead
|
||||
2. **Auto-sync:** Changes automatically written to `userbase-config.json` and types to `userbase-types.d.ts`
|
||||
3. **In Production:** `mode: "code"` - Configuration read from `userbase-config.json`, no database overhead
|
||||
|
||||
## Why devFsVitePlugin?
|
||||
|
||||
@@ -242,8 +242,8 @@ The `devFsVitePlugin` + `devFsWrite` combination provides a workaround by using
|
||||
|
||||
## Want to learn more?
|
||||
|
||||
- [Cloudflare Integration Documentation](https://docs.bknd.io/integration/cloudflare)
|
||||
- [Hybrid Mode Guide](https://docs.bknd.io/usage/introduction#hybrid-mode)
|
||||
- [Mode Helpers Documentation](https://docs.bknd.io/usage/introduction#mode-helpers)
|
||||
- [Cloudflare Integration Documentation](https://docs.userbase.io/integration/cloudflare)
|
||||
- [Hybrid Mode Guide](https://docs.userbase.io/usage/introduction#hybrid-mode)
|
||||
- [Mode Helpers Documentation](https://docs.userbase.io/usage/introduction#mode-helpers)
|
||||
- [Discord Community](https://discord.gg/952SFk8Tb8)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user