Files
fullstack-starter/README.md
T
imbytecat 27e5f3c76f chore(vite): remove server block (no need to pin port 3000 strict)
vite default already binds 3000 if available; no real requirement to
strict-port. AGENTS.md / README.md synced.
2026-04-25 17:19:27 +08:00

111 lines
4.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# fullstack-starter
一个**单二进制**的全栈应用 starter——`bun run compile` 出来的 `./server` 文件就是你要部署的全部产物,自带 HTTP 服务、SSR、API、嵌入式 SQL 迁移,运行时不依赖 Node、不依赖源码、不依赖外部 migration 目录。
技术栈:Bun · TanStack Start (React 19 SSR) · ORPC(契约优先 API)· Drizzle ORM · PostgreSQL · Tailwind v4 · Biome。
## 为什么用这个
- **部署最简**:发布只拷一个二进制文件。先 `./server migrate``./server`,完事。
- **契约优先**:在 `*.contract.ts` 用 Zod 定义一次,前端、后端、OpenAPI 文档自动同步。
- **类型严格**TypeScript strict,杜绝 `any` / `@ts-ignore` / `as any` 等类型逃逸。
- **开箱可跑**:路径别名、文件路由、ORPC 接线、Tailwind、热重载、错误页全部预接好。
## 快速开始
```bash
cp .env.example .env # 把里面的 DATABASE_URL 改成你的 Postgres
bun install
bun run db:push # 开发期:把 schema 直接同步到 DB(不写 migration 文件)
bun run dev # http://localhost:3000
```
打开浏览器:
- `http://localhost:3000/` — Todo 示例页
- `http://localhost:3000/api/docs` — Scalar 渲染的 API 文档
## 目录结构(你需要关心的部分)
```
src/
├── routes/ # 文件路由:页面 + API 端点
├── server/
│ ├── api/
│ │ ├── contracts/ # Zod 契约(client / server 共享)
│ │ └── routers/ # 业务实现
│ └── db/ # Drizzle schema + 嵌入式 migrations
├── client/ # 前端 hooks、ORPC 客户端
└── components/ # UI 组件
```
## 加一个功能(以 `post` 为例)
每一步都很短,按顺序填即可:
1. **建表**`src/server/db/schema/post.ts` 定义 `postTable`,记得展开 `...generatedFields`(自动注入 `id` / `createdAt` / `updatedAt`)。
2. **导出表**:在 `src/server/db/schema/index.ts``export * from './post'`
3. **写契约**`src/server/api/contracts/post.contract.ts``drizzle-zod` 从表派生 Zod schema。
4. **挂契约**:在 `src/server/api/contracts/index.ts``post` 加进 `contract` 对象。
5. **写实现**`src/server/api/routers/post.router.ts` 实现 `os.post.*.handler(...)`
6. **挂路由**:在 `src/server/api/routers/index.ts``post` 加进 `router` 对象。
7. **写前端 hook**`src/client/queries/post.ts` 导出 `useInvalidatePosts` 等失效辅助。
8. **写页面**`src/routes/<page>.tsx``useSuspenseQuery` 读、`mutate` 写;mutation 的 `onSuccess` 调用第 7 步的 helper。
9. **生成 migration**`bun run db:generate` 把 SQL 写到 `./drizzle/` 并嵌入二进制。
完工。`bun run dev` 已自动热重载。
## 部署
**永远先 migrate 再 serve**。Migration 已嵌入二进制;部署只发一个 `./server` 文件。
```bash
./server migrate # 应用嵌入式 migration(用 $DATABASE_URL
./server # 启动 HTTP 服务(默认子命令)
./server --help # 列出所有子命令
```
仓库自带 `compose.yaml`(一次性 `migrate` 服务先跑完,再启动 `app`):
```bash
docker compose up --build
```
Kubernetes 上:把 `./server migrate` 放进 initContainer 或 Helm `pre-upgrade` Job,主容器跑 `./server`
## 脚本一览
| 命令 | 作用 |
| --- | --- |
| `bun run dev` | Vite 开发服务器(默认端口 3000) |
| `bun run build` | 构建到 `.output/``bun run compile` 会用到) |
| `bun run compile` | 生成单二进制 `out/server-<target>` |
| `bun run typecheck` | TypeScript 类型检查 |
| `bun run test` | 运行所有 `*.test.ts` |
| `bun run fix` | Biome 格式化 + lint + 整理 imports |
| `bun run db:push` | 开发期:直接同步 schema 到 DB(不写 migration 文件) |
| `bun run db:generate` | 写 SQL migration 到 `./drizzle/` 并嵌入二进制 |
| `bun run db:embed` | 仅重生 `migrations.gen.ts`(手改了 `./drizzle/*.sql` 后用) |
| `bun run db:migrate` | 通过 drizzle-kit 在本地应用 migration(开发便利) |
| `bun run db:studio` | Drizzle Studio(可视化 DB |
跨平台编译:`bun run compile:{linux,darwin,windows}[:arch]`
## 端点
| 路径 | 用途 |
| --- | --- |
| `/` | Todo 示例 UI |
| `/health` | 存活探针(不查 DB,纯文本 `ok` |
| `/api/rpc` | ORPC RPC 端点(client 直连) |
| `/api/docs` | Scalar 渲染的 API 文档 |
| `/api/spec.json` | OpenAPI spec |
## 提交前
```bash
bun run fix && bun run typecheck && bun run test
```
没有 CI、没有 pre-commit hook——上面三条由你自觉跑。