README.md 6.8 K raw
1
# bhvr đŸĻĢ
2
3
![cover](https://cdn.stevedylan.dev/ipfs/bafybeievx27ar5qfqyqyud7kemnb5n2p4rzt2matogi6qttwkpxonqhra4)
4
5
A full-stack TypeScript monorepo starter with shared types, using Bun, Hono, Vite, and React
6
7
## Why bhvr?
8
9
While there are plenty of existing app building stacks out there, many of them are either bloated, outdated, or have too much of a vendor lock-in. bhvr is built with the opinion that you should be able to deploy your client or server in any environment while also keeping type saftey.
10
11
## Features
12
13
- **Full-Stack TypeScript**: End-to-end type safety between client and server
14
- **Shared Types**: Common type definitions shared between client and server
15
- **Monorepo Structure**: Organized as a workspaces-based monorepo
16
- **Modern Stack**:
17
  - [Bun](https://bun.sh) as the JavaScript runtime
18
  - [Hono](https://hono.dev) as the backend framework
19
  - [Vite](https://vitejs.dev) for frontend bundling
20
  - [React](https://react.dev) for the frontend UI
21
22
## Project Structure
23
24
```
25
.
26
├── client/               # React frontend
27
├── server/               # Hono backend
28
├── shared/               # Shared TypeScript definitions
29
│   └── src/types/        # Type definitions used by both client and server
30
└── package.json          # Root package.json with workspaces
31
```
32
33
### Server
34
35
bhvr uses Hono as a backend API for it's simplicity and massive ecosystem of plugins. If you have ever used Express then it might feel familiar. Declaring routes and returning data is easy.
36
37
```
38
server
39
├── bun.lock
40
├── package.json
41
├── README.md
42
├── src
43
│   └── index.ts
44
└── tsconfig.json
45
```
46
47
```typescript src/index.ts
48
import { Hono } from 'hono'
49
import { cors } from 'hono/cors'
50
import type { ApiResponse } from 'shared/dist'
51
52
const app = new Hono()
53
54
app.use(cors())
55
56
app.get('/', (c) => {
57
  return c.text('Hello Hono!')
58
})
59
60
app.get('/hello', async (c) => {
61
62
  const data: ApiResponse = {
63
    message: "Hello BHVR!",
64
    success: true
65
  }
66
67
  return c.json(data, { status: 200 })
68
})
69
70
export default app
71
```
72
73
If you wanted to add a database to Hono you can do so with a multitude of Typescript libraries like [Supabase](https://supabase.com), or ORMs like [Drizzle](https://orm.drizzle.team/docs/get-started) or [Prisma](https://www.prisma.io/orm)
74
75
### Client
76
77
bhvr uses Vite + React Typescript template, which means you can build your frontend just as you would with any other React app. This makes it flexible to add UI components like [shadcn/ui](https://ui.shadcn.com) or routing using [React Router](https://reactrouter.com/start/declarative/installation).
78
79
```
80
client
81
├── eslint.config.js
82
├── index.html
83
├── package.json
84
├── public
85
│   └── vite.svg
86
├── README.md
87
├── src
88
│   ├── App.css
89
│   ├── App.tsx
90
│   ├── assets
91
│   ├── index.css
92
│   ├── main.tsx
93
│   └── vite-env.d.ts
94
├── tsconfig.app.json
95
├── tsconfig.json
96
├── tsconfig.node.json
97
└── vite.config.ts
98
```
99
100
```typescript src/App.tsx
101
import { useState } from 'react'
102
import beaver from './assets/beaver.svg'
103
import { ApiResponse } from 'shared'
104
import './App.css'
105
106
const SERVER_URL = import.meta.env.VITE_SERVER_URL || "http://localhost:3000"
107
108
function App() {
109
  const [data, setData] = useState<ApiResponse | undefined>()
110
111
  async function sendRequest() {
112
    try {
113
      const req = await fetch(`${SERVER_URL}/hello`)
114
      const res: ApiResponse = await req.json()
115
      setData(res)
116
    } catch (error) {
117
      console.log(error)
118
    }
119
  }
120
121
  return (
122
    <>
123
      <div>
124
        <a href="https://github.com/stevedylandev/bhvr" target="_blank">
125
          <img src={beaver} className="logo" alt="beaver logo" />
126
        </a>
127
      </div>
128
      <h1>bhvr</h1>
129
      <h2>Bun + Hono + Vite + React</h2>
130
      <p>A typesafe fullstack monorepo</p>
131
      <div className="card">
132
        <button onClick={sendRequest}>
133
          Call API
134
        </button>
135
        {data && (
136
          <pre className='response'>
137
            <code>
138
            Message: {data.message} <br />
139
            Success: {data.success.toString()}
140
            </code>
141
          </pre>
142
        )}
143
      </div>
144
      <p className="read-the-docs">
145
        Click the beaver to learn more
146
      </p>
147
    </>
148
  )
149
}
150
151
export default App
152
```
153
154
### Shared
155
156
The Shared package is used for anything you want to share between the Server and Client. This could be types or libraries that you use in both the enviorments.
157
158
```
159
shared
160
├── package.json
161
├── src
162
│   ├── index.ts
163
│   └── types
164
│       └── index.ts
165
└── tsconfig.json
166
```
167
168
Inside the `src/index.ts` we export any of our code from the folders so it's usabe in other parts of the monorepo
169
170
```typescript
171
export * from "./types"
172
```
173
174
By running `bun run dev` or `bun run build` it will compile and export the packages from `shared` so it can be used in either `client` or `server`
175
176
```typescript
177
import { ApiResponse } from 'shared'
178
```
179
180
## Getting Started
181
182
### Quick Start
183
184
You can start a new bhvr project using the [CLI](https://github.com/stevedylandev/create-bhvr)
185
186
```bash
187
bun create bhvr
188
```
189
190
### Installation
191
192
```bash
193
# Install dependencies for all workspaces
194
bun install
195
```
196
197
### Development
198
199
```bash
200
# Run shared types in watch mode, server, and client all at once
201
bun run dev
202
203
# Or run individual parts
204
bun run dev:shared  # Watch and compile shared types
205
bun run dev:server  # Run the Hono backend
206
bun run dev:client  # Run the Vite dev server for React
207
```
208
209
### Building
210
211
```bash
212
# Build everything
213
bun run build
214
215
# Or build individual parts
216
bun run build:shared  # Build the shared types package
217
bun run build:client  # Build the React frontend
218
```
219
220
### Deployment
221
222
Deplying each piece is very versatile and can be done numerous ways, and exploration into automating these will happen at a later date. Here are some references in the meantime.
223
224
**Client**
225
- [Orbiter](https://orbiter.host)
226
- [GitHub Pages](https://vite.dev/guide/static-deploy.html#github-pages)
227
- [Netlify](https://vite.dev/guide/static-deploy.html#netlify)
228
- [Cloudflare Pages](https://vite.dev/guide/static-deploy.html#cloudflare-pages)
229
230
**Server**
231
- [Cloudflare Worker](https://gist.github.com/stevedylandev/4aa1fc569bcba46b7169193c0498d0b3)
232
- [Bun](https://hono.dev/docs/getting-started/bun)
233
- [Node.js](https://hono.dev/docs/getting-started/nodejs)
234
235
## Type Sharing
236
237
Types are automatically shared between the client and server thanks to the shared package and TypeScript path aliases. You can import them in your code using:
238
239
```typescript
240
import { ApiResponse } from '@shared/types';
241
```
242
243
## Learn More
244
245
- [Bun Documentation](https://bun.sh/docs)
246
- [Vite Documentation](https://vitejs.dev/guide/)
247
- [React Documentation](https://react.dev/learn)
248
- [Hono Documentation](https://hono.dev/docs)
249
- [TypeScript Documentation](https://www.typescriptlang.org/docs/)