一个功能精简但覆盖主流全栈技术栈的学校后台管理系统, 用来在一个项目里把 Bun 全栈开发的优势与坑都亲身体会一遍。 后端 Elysia + Drizzle +
bun:sqlite,前端 Vue 3 + Vite, 生产态是单进程单端口的「真·Bun 单体」。
| 层 | 选型 |
|---|---|
| 运行时 / 工具链 | Bun (install/run/test/build/fmt 全内置) |
| 后端框架 | Elysia (Bun 原生,t schema 类型推导) |
| HTTP 客户端(前端) | @elysiajs/eden (从后端 App 类型生成前端 client,端到端类型安全) |
| ORM | Drizzle ORM |
| 数据库驱动 | bun:sqlite (Bun 内置,零原生编译) |
| 密码哈希 | Bun.password (内置 bcrypt) |
| 令牌 | Web Crypto HMAC-SHA256 (见下方「坑 #1」) |
| 前端 | Vue 3 + Vite (SFC + HMR) |
| 校验 | 后端 Elysia t / 前端 Zod v4 |
| 样式 | Tailwind CSS v3.4 |
| 路由 | vue-router |
| 测试 | bun test (用 app.handle(Request) 模式,不绑定端口) |
| 部署 | bun build --compile 单二进制 + 多阶段 Dockerfile |
四个模块均为精简 CRUD,列表统一支持分页 + 关键字搜索 + 关联筛选:
- 班级 Classes:年级 + 班级名
- 教师 Teachers:姓名 + 学科 + 职称 + 电话
- 学生 Students:姓名 + 性别 + 出生日期 + 所属班级(1:N)
- 课程 Courses:名称 + 授课教师(1:N)+ 上课班级(1:N)+ 课时
外加:管理员登录(JWT)、仪表盘(各实体计数)。
bun install
bun run migrate # 建表(首次)
bun run seed # 注入 admin 账号(首次)
bun run dev # 同时起 Bun :3000 与 Vite :5173打开 http://localhost:5173 ,登录:
- 用户名:
admin - 密码:
admin123
开发态前端走 Vite
:5173,/api由 Vite 代理到 Bun:3000。
bun install
bun run build # vite build 生成 dist/ + bun build --compile 生成单二进制 ./server
./server # Windows 下为 server.exe;监听 $PORT(默认 3000)浏览器直接访问 http://localhost:3000 —— 同一端口同时托管前端 SPA 与 /api。
启动即自动建表并注入 admin 账号(ensureAdmin() 幂等),无需手动 migrate/seed。
docker build -t bun-school-admin .
docker run -p 3000:3000 -v school-data:/app bun-school-admin镜像内 CMD ["./server"] 自举数据库;SQLite 文件落在 /app,挂卷即可持久化。
| 脚本 | 说明 |
|---|---|
bun run dev |
前后端同时热重载(concurrently) |
bun run build:web |
仅前端 Vite 构建 |
bun run build |
前端构建 + 后端单二进制编译 |
bun run migrate |
执行建表(幂等 CREATE TABLE IF NOT EXISTS) |
bun run seed |
注入 admin 账号 |
bun run start |
直接跑 src/server/index.ts |
bun test |
后端测试(10 个用例) |
bun-school-admin/
├── package.json / tsconfig.json / bunfig.toml
├── vite.config.ts # root=src/web, outDir=../dist, proxy /api
├── drizzle.config.ts
├── Dockerfile / .dockerignore
├── src/
│ ├── server/
│ │ ├── index.ts # 入口:ensureAdmin() + app.listen()
│ │ ├── app.ts # 组装 Elysia 实例(导出 App 类型供 Eden)
│ │ ├── plugins/auth.ts # withAuth():derive+onBeforeHandle 鉴权
│ │ ├── routes/ # auth / dashboard / classes / teachers / students / courses
│ │ ├── db/ # index(bun:sqlite+drizzle) / schema / migrate(raw SQL) / seed
│ │ └── lib/ # password(Bun.password) / jwt(Web Crypto) / crud(通用 CRUD 工厂)
│ ├── shared/ # types.ts(DTO) / zod.ts(表单校验)
│ └── web/ # Vue 前端(views / components / composables / router)
├── dist/ # 前端构建产物(被 server 静态托管)
└── tests/api.test.ts # 10 个后端用例
- 后端
app.ts导出App类型;前端src/web/api/client.ts用edenTreaty<App>(base)生成 client,改接口前端编译期即报错。 - 校验分层:后端 HTTP 入参用 Elysia
t(保 Eden 联动); 前端表单用shared/zod.ts的 Zod 做校验(与后端结构保持一致)。
以下条目均为本项目真实踩到的,不是照搬文档。
- 单一工具链:
bun install/run/test/build全内置,无需拼 node/npm/tsc/jest/vite。 - 原生 TypeScript:后端
.ts直接跑,零编译配置。 - 零原生依赖的后端能力:
Bun.password(哈希)、bun:sqlite(DB) 全是内置, 彻底避开 better-sqlite3 / bcrypt 的原生编译坑——Bun 最硬的卖点。 - 端到端类型安全:Elysia + Eden 让 Vue 拿到后端 HTTP 类型。
- 关系型 CRUD 很顺:Drizzle +
bun:sqlite让 1:N 关联、分页、计数类型化且简洁。 - 极简部署:
bun build --compile一个二进制 + 单 Dockerfile 单端口。 - 快:安装 / 冷启动 / 运行时均显著快于 Node 同构方案。
Bun.jwt在本版本是undefined(实测 Bun 1.3.14)。import { jwt } from "bun"后jwt为undefined,直接调用会崩。 → 已改用 Web Crypto 的 HMAC-SHA256 手写 JWT(src/server/lib/jwt.ts)。 若升级 Bun 后Bun.jwt可用,可平滑换回。- 前端 SFC 不能
bun build:Bun 打包器无插件系统,Vue SFC 必须 Vite 打包。 → 「真·Bun 单体」只在运行态成立;开发/构建期前端仍走 Vite。纯bun build需放弃 SFC 或换 React。 - Elysia 1.4 的「仅含 hook 的插件」经
.use()挂载时不执行 hook: 一开始把鉴权写成export const auth = new Elysia().onBeforeHandle(...)再.use(auth), 结果发现子路由的鉴权根本不触发。 → 改为export function withAuth(): Elysia {...},在每个路由的同一实例上链式调用 (crudRoutes返回withAuth().get(...),dashboard 也withAuth().get(...))。 - 迁移没用 drizzle-kit:演示项目直接
ensureSchema()跑CREATE TABLE IF NOT EXISTS原始 SQL(src/server/db/migrate.ts), 避免引入迁移文件依赖,seed 也更简单。正式项目可换 drizzle-kit。 - 受限环境下 Vite 的
emptyOutDir会失败:Vite 的prepare-out-dir把fs.rmSync路由到「安全删除→回收站」,在部分环境(如本机被拦截)会直接让构建报错。 → 已在vite.config.ts设emptyOutDir: false,改由build脚本用rm -rf dist预清理。 bun:sqlite仅本地文件:演示够用;上远程 DB 需换 Postgres +postgres驱动。- 调试/可观测生态弱于 Node:断点、APM、devtools 插件丰富度不及 Node 生态。
- 版本迭代快:Bun 偶有破坏性变更(如
Bun.jwt的可用性),锁版本 + 关注 changelog 必要。
- ✅
bun test:10/10 通过(auth 401/200、鉴权中间件、classes CRUD、courses/students 关联查询)。 - ✅
bun run build:web:Vite 构建成功(dist/index.html + assets)。 - ✅
bun build --compile:产出单二进制server(Windows 为server.exe,约 99MB,内嵌 Bun 运行时)。 - ✅ 编译后二进制端到端实测:启动即建表 + 注入 admin;
/health正常;登录返回 JWT; 带 token 访问/api/dashboard返回计数、无 token 返回 401;POST /api/classes正常; SPA/返回 200(同端口托管前端)。
- 角色细分(admin / teacher 只读自己课程)
- 学生↔课程 M:N 选课 + 成绩管理
- 列表导出 Excel / 批量导入
- SQLite 换 Postgres,对比 ORM 配置差异