imbytecat cc3a5dc5ad feat(logging): 引入 LogTape 替换 console.* 为结构化日志
为什么选 LogTape(2026 实测):
- pino 在 bun build --compile 编译产物里因 worker_threads + 动态 require 在
  /\$bunfs/ 虚拟文件系统中崩溃,与单二进制部署核心目标冲突;
- LogTape 零依赖(5.3KB)、零 worker、纯 ESM、原生 Bun 导出条件,runtime
  agnostic,配合 configureSync 完美兼容 --bytecode 模式(无裸 top-level await);
- 一等公民集成:@logtape/drizzle-orm(SQL 查询日志)、@logtape/otel(后续
  OpenTelemetry sink 留扩展点)。

变更:
- src/server/logger.ts: configureSync 引导 + getLogger 重导出。format 默认
  process.stdout.isTTY ? pretty : json,可经 LOG_FORMAT 显式覆盖(绕开 Bun
  bundler 把 process.env.NODE_ENV 在 --minify 时 inline 成字面量的特殊处理)。
- src/server/api/interceptors.ts: logError 改用 getLogger(['api']).error(...) +
  结构化 properties,弃 logger.error 顶层 API。
- src/cli/migrate.ts: 所有 console.log 改走 getLogger(['cli','migrate']),logger
  在 run() 内 lazy-import 以保持 citty subcommand 模块体 side-effect-free。
- src/server/db/index.ts: env.LOG_DB=true 时挂 DrizzleLogger 适配器,SQL 查询
  按类别 ['db'] 在 debug 级输出(含 query/params/formattedQuery 三字段)。

新增 env 旋钮(t3-oss 校验):
- LOG_LEVEL: trace|debug|info|warning|error|fatal,默认 info
- LOG_FORMAT: pretty|json,默认 TTY 自动选
- LOG_DB: stringbool,默认 false

端到端验证(compose + Postgres 18-alpine):
- TTY 终端:pretty 输出含  图标 + ANSI 彩色 + 类别·路径 ✓
- 管道/Docker:JSON Lines 一行一条,含 @timestamp/level/logger/properties ✓
- LOG_FORMAT=pretty 强制覆盖 ✓
- ./server migrate 应用 migration 并经 logger 输出 ✓
- ./server serve + RPC round-trip:interceptor logError 与 drizzle SQL 日志
  在生产 JSON 模式下结构化输出 ✓
- fix / typecheck / test 3/3 / build / compile 117M 二进制全绿
2026-04-25 16:04:31 +08:00

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、热重载、错误页全部预接好。

快速开始

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.tsexport * from './post'
  3. 写契约src/server/api/contracts/post.contract.tsdrizzle-zod 从表派生 Zod schema。
  4. 挂契约:在 src/server/api/contracts/index.tspost 加进 contract 对象。
  5. 写实现src/server/api/routers/post.router.ts 实现 os.post.*.handler(...)
  6. 挂路由:在 src/server/api/routers/index.tspost 加进 router 对象。
  7. 写前端 hooksrc/client/queries/post.ts 导出 useInvalidatePosts 等失效辅助。
  8. 写页面src/routes/<page>.tsxuseSuspenseQuery 读、mutate 写;mutation 的 onSuccess 调用第 7 步的 helper。
  9. 生成 migrationbun run db:generate 把 SQL 写到 ./drizzle/ 并嵌入二进制。

完工。bun run dev 已自动热重载。

部署

永远先 migrate 再 serve。Migration 已嵌入二进制;部署只发一个 ./server 文件。

./server migrate            # 应用嵌入式 migration(用 $DATABASE_URL
./server                    # 启动 HTTP 服务(默认子命令)
./server --help             # 列出所有子命令

仓库自带 compose.yaml(一次性 migrate 服务先跑完,再启动 app):

docker compose up --build

Kubernetes 上:把 ./server migrate 放进 initContainer 或 Helm pre-upgrade Job,主容器跑 ./server

脚本一览

命令 作用
bun run dev Vite 开发服务器(端口 3000strict)
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

提交前

bun run fix && bun run typecheck && bun run test

没有 CI、没有 pre-commit hook——上面三条由你自觉跑。

S
Description
No description provided
Readme 2.8 MiB
Languages
TypeScript 98.7%
Dockerfile 1%
JavaScript 0.2%