# Fullstack Starter (SQLite) 一个基于 **TanStack Start + Bun + Tauri + SQLite** 的全栈桌面应用脚手架。 包含一个完整的 **Todo List** 示例,展示了从前端到后端的完整数据流。 ## 技术栈 | 层级 | 技术 | |------|------| | 前端框架 | React 19 + TanStack Router (文件路由) | | 状态管理 | TanStack Query | | 样式 | Tailwind CSS v4 | | RPC 通信 | ORPC (类型安全,契约优先) | | 数据库 | SQLite (Bun 内置) + Drizzle ORM | | 桌面壳 | Tauri v2 | | 运行时 | Bun | | 构建 | Vite + Turbo | ## 快速开始 ### 前置要求 - [Bun](https://bun.sh/) >= 1.0 - [Rust](https://www.rust-lang.org/) (仅 Tauri 桌面应用需要) ### 安装与运行 ```bash # 1. 克隆项目 git clone cd fullstack-starter-SQLite # 2. 安装依赖 bun install # 3. 初始化数据库 bun run db:init # 4. 启动开发服务器 bun run dev:vite # 仅 Web (http://localhost:3000) bun run dev # Tauri 桌面应用 + Web ``` ### 构建 ```bash bun run build:vite # 构建 Web 版本 bun run build # 构建 Tauri 桌面安装包 ``` ## 项目结构 ``` ├── src/ │ ├── components/ # 可复用组件 │ │ ├── Error.tsx # 错误边界组件 │ │ └── NotFound.tsx # 404 页面组件 │ │ │ ├── db/ # 数据库层 │ │ ├── index.ts # 数据库连接 │ │ └── schema/ # Drizzle 表定义 │ │ ├── index.ts # Schema 导出入口 │ │ └── todo.ts # Todo 表定义 │ │ │ ├── orpc/ # RPC 层 (后端 API) │ │ ├── contracts/ # 契约定义 (输入/输出 Schema) │ │ │ └── todo.ts # Todo API 契约 │ │ ├── handlers/ # 业务逻辑实现 │ │ │ └── todo.ts # Todo CRUD 处理器 │ │ ├── middlewares/ # 中间件 │ │ │ └── db.ts # 数据库注入中间件 │ │ ├── contract.ts # 契约聚合 │ │ ├── router.ts # 路由聚合 │ │ ├── client.ts # 同构客户端 (SSR/CSR) │ │ ├── server.ts # 服务端实例 │ │ └── index.ts # 导出入口 │ │ │ ├── routes/ # 页面路由 (文件路由) │ │ ├── __root.tsx # 根布局 │ │ ├── index.tsx # 首页 (Todo List) │ │ └── api/ │ │ └── rpc.$.ts # RPC HTTP 端点 │ │ │ ├── integrations/ # 第三方库集成 │ ├── lib/ # 工具函数 │ ├── env.ts # 环境变量验证 │ ├── router.tsx # 路由配置 │ └── styles.css # 全局样式 │ ├── scripts/ │ └── init-db.ts # 数据库初始化脚本 │ ├── src-tauri/ # Tauri 桌面应用配置 ├── data/ # SQLite 数据库文件 (gitignore) └── drizzle.config.ts # Drizzle 配置 ``` ## 开发指南 ### 添加新功能的步骤 以添加一个 "Note" 功能为例: #### 1. 定义数据库 Schema ```typescript // src/db/schema/note.ts import { sql } from 'drizzle-orm' import { integer, sqliteTable, text } from 'drizzle-orm/sqlite-core' export const noteTable = sqliteTable('note', { id: text('id').primaryKey().$defaultFn(() => crypto.randomUUID()), content: text('content').notNull(), createdAt: integer('created_at', { mode: 'timestamp' }) .notNull() .default(sql`(unixepoch())`), }) ``` ```typescript // src/db/schema/index.ts export * from './todo.ts' export * from './note.ts' // 添加导出 ``` #### 2. 定义 API 契约 ```typescript // src/orpc/contracts/note.ts import { oc } from '@orpc/contract' import { z } from 'zod' export const note = { list: oc.output(z.array(noteSchema)), create: oc.input(z.object({ content: z.string() })).output(noteSchema), } ``` #### 3. 实现业务逻辑 ```typescript // src/orpc/handlers/note.ts import { os } from '@/orpc/server' import { dbProvider } from '@/orpc/middlewares/db' import { noteTable } from '@/db/schema' export const list = os.note.list .use(dbProvider) .handler(async ({ context }) => { return context.db.select().from(noteTable) }) export const create = os.note.create .use(dbProvider) .handler(async ({ context, input }) => { const [note] = await context.db.insert(noteTable).values(input).returning() return note }) ``` #### 4. 注册到路由 ```typescript // src/orpc/contract.ts import { note } from './contracts/note' export const contract = { todo, note } // src/orpc/router.ts import * as note from './handlers/note' export const router = os.router({ todo, note }) ``` #### 5. 在页面中使用 ```typescript // src/routes/notes.tsx import { orpc } from '@/orpc' import { useSuspenseQuery, useMutation } from '@tanstack/react-query' const NotesPage = () => { const { data: notes } = useSuspenseQuery(orpc.note.list.queryOptions()) const createNote = useMutation(orpc.note.create.mutationOptions()) // ... } ``` ### 常用命令 | 命令 | 说明 | |------|------| | `bun run dev` | 启动 Tauri + Vite 开发服务器 | | `bun run dev:vite` | 仅启动 Vite 开发服务器 | | `bun run build` | 完整构建 (Tauri 桌面应用) | | `bun run build:vite` | 仅构建 Web 版本 | | `bun run db:init` | 初始化/重置数据库 | | `bun run db:studio` | 打开 Drizzle Studio | | `bun run typecheck` | TypeScript 类型检查 | | `bun run fix` | 自动修复格式和 Lint 问题 | ### 代码规范 - **格式化**: 使用 Biome,2 空格缩进,单引号 - **导入**: 使用 `@/*` 路径别名 - **组件**: 箭头函数组件 - **命名**: 文件 kebab-case,组件 PascalCase ## 核心概念 ### ORPC 数据流 ``` 前端组件 ↓ useSuspenseQuery / useMutation ORPC 客户端 (src/orpc/client.ts) ↓ 自动选择 SSR 直调 / CSR HTTP 契约验证 (src/orpc/contracts/) ↓ 输入/输出类型安全 处理器 (src/orpc/handlers/) ↓ 业务逻辑 中间件 (src/orpc/middlewares/) ↓ 注入数据库连接 Drizzle ORM ↓ 类型安全查询 SQLite 数据库 ``` ### 同构渲染 - **SSR**: 服务端直接调用 router,无 HTTP 开销 - **CSR**: 客户端通过 `/api/rpc` 端点调用 ### 数据库 - SQLite 文件存储在 `./data/app.db` - 使用 WAL 模式提高并发性能 - 单例模式管理连接 ## 许可证 MIT