一套代码,四种技术栈,一个仓库搞定前后端全栈开发。
在 2026 年的前端开发生态中,Monorepo 已经成为大型项目的标配。而 Turborepo 凭借其智能缓存和任务编排能力,成为了 Monorepo 构建工具的事实标准。
今天,我将手把手带你搭建一个生产级全栈 Monorepo,包含四种不同技术栈的应用,以及数据库、缓存等主流中间件。
项目技术栈一览
我们计划构建的应用包括:
- Web 应用:TanStack Start(React 全栈框架,基于 Vite)
- Admin 后台:Vue 3(轻量级后台管理)
- Console 控制台:Next.js(企业级控制台)
- Backend API:Hono(超快边缘计算框架)
基础设施:
- 数据库:PostgreSQL + Drizzle ORM
- 缓存 / 队列:Redis + BullMQ(可选)
- 包管理器:pnpm(Workspace 原生支持)
- 构建系统:Turborepo
第一步:初始化 Monorepo
使用官方脚手架快速创建项目:
# 使用 pnpm 创建(推荐)
pnpm dlx create-turbo@latest my-monorepo
cd my-monorepo
根据提示选择 pnpm 作为包管理器。推荐 pnpm 是因为它对 Workspace 有最好的支持,且依赖管理更高效。
第二步:规划项目结构
按照 Turborepo 的最佳实践,将代码分为 apps/(可部署应用)和 packages/(共享库):
my-monorepo/
├── apps/
│ ├── web/ # TanStack Start (React)
│ ├── admin/ # Vue 3 后台
│ ├── console/ # Next.js 控制台
│ └── backend/ # Hono API 服务
├── packages/
│ ├── ui/ # 共享 UI 组件库
│ ├── database/ # Drizzle ORM Schema + 客户端
│ ├── redis/ # Redis 客户端封装
│ ├── types/ # 共享 TypeScript 类型
│ └── config/ # 共享配置(ESLint, TypeScript, Tailwind)
├── package.json
├── pnpm-workspace.yaml
└── turbo.json
在 pnpm-workspace.yaml 中声明工作区:
packages:
- "apps/*"
- "packages/*"
apps/ 存放的是可部署的应用,packages/ 存放的是被应用消费的共享代码。这是一个约定而非强制要求,但它能帮你建立清晰的职责边界。
第三步:配置 Turborepo
turbo.json 是 Turborepo 的核心配置文件,定义了任务依赖关系和缓存策略。
{
"$schema": "https://turbo.build/schema.json",
"tasks": {
"build": {
"dependsOn": ["^build"],
"outputs": [".next/**", "dist/**", "!.next/cache/**"]
},
"dev": {
"cache": false,
"persistent": true
},
"lint": {
"outputs": []
},
"test": {
"dependsOn": ["build"],
"outputs": ["coverage/**"]
},
"type-check": {
"dependsOn": ["^build"],
"outputs": []
}
},
"remoteCache": {
"enabled": true
}
}
理解 dependsOn 是掌握 Turborepo 的关键:
"dependsOn": ["^build"]:在执行当前包的 build 之前,先执行它所有 workspace 依赖包的 build"dependsOn": ["build"](无^):在同一包内先执行 build,再执行当前任务
outputs 字段告诉 Turborepo 哪些目录需要缓存。Next.js 应用的 .next/** 和 Vite 应用的 dist/** 是最常见的输出目录。
第四步:创建共享数据库包(Drizzle ORM)
在 packages/database/ 中集中管理所有数据库 Schema 和迁移:
// packages/database/src/schema/index.ts
import { pgTable, uuid, varchar, timestamp, jsonb } from 'drizzle-orm/pg-core';
export const users = pgTable('users', {
id: uuid('id').defaultRandom().primaryKey(),
username: varchar('username', { length: 50 }).notNull().unique(),
email: varchar('email', { length: 255 }).notNull().unique(),
// ... 更多字段
});
// packages/database/src/client.ts
import { drizzle } from 'drizzle-orm/node-postgres';
import { Pool } from 'pg';
import * as schema from './schema';
const pool = new Pool({
connectionString: process.env.DATABASE_URL,
});
export const db = drizzle(pool, { schema });
设计原则:将 Drizzle Schema 放在其所属应用的 src/db/ 下,由一个应用独享数据库绑定,其他应用通过 RPC 或 API 调用访问数据。如果使用共享 packages/database,要确保只有一个应用执行迁移操作。
第五步:配置 Redis 与 BullMQ
在 packages/redis/ 中封装 Redis 客户端,供后台应用和队列使用:
// packages/redis/src/index.ts
import Redis from 'ioredis';
export const redis = new Redis(process.env.REDIS_URL || 'redis://localhost:6379');
// 可选:BullMQ 队列
import { Queue } from 'bullmq';
export const emailQueue = new Queue('email', {
connection: redis,
});
Drizzle ORM 从 0.44 版本开始原生支持查询缓存,可以直接集成 Upstash Redis 或自定义缓存层:
import { upstashCache } from 'drizzle-orm/cache/upstash';
import { drizzle } from 'drizzle-orm/...';
const db = drizzle(process.env.DB_URL!, {
cache: upstashCache({
url: process.env.UPSTASH_URL,
token: process.env.UPSTASH_TOKEN,
global: true,
config: { ex: 60 } // 缓存 60 秒
})
});
第六步:创建各个应用
在根目录的 package.json 中添加启动脚本,统一通过 Turborepo 管理:
{
"scripts": {
"dev": "turbo run dev",
"build": "turbo run build",
"lint": "turbo run lint",
"type-check": "turbo run type-check",
"clean": "turbo run clean && rm -rf node_modules"
}
}
Web 应用(TanStack Start)
TanStack Start 基于 Vite,开发启动速度快,适合前端主站。
cd apps/web
pnpm create @tanstack/start@latest . --template react
Admin 后台(Vue 3)
使用 Vue 官方脚手架创建轻量级后台:
cd apps/admin
pnpm create vue@latest .
# 选择 TypeScript、Vue Router、Pinia 等特性
Console 控制台(Next.js)
Next.js 与 Turborepo 有官方级别的集成支持,缓存效果极佳:
cd apps/console
pnpm create next-app@latest . --typescript --tailwind --eslint
Backend API(Hono)
Hono 是超快的边缘计算 Web 框架,适合作为 API 网关:
cd apps/backend
pnpm create hono@latest .
# 选择 Node.js 运行时
在 Hono 中配置环境变量验证(推荐使用 Zod):
// apps/backend/src/env.ts
import { z } from 'zod';
export const env = z.object({
DATABASE_URL: z.string().url(),
REDIS_URL: z.string().url(),
JWT_SECRET: z.string().min(32),
}).parse(process.env);
第七步:内部包引用
共享包通过 workspace: 协议在应用中被引用:
// apps/web/package.json
{
"dependencies": {
"@repo/ui": "workspace:*",
"@repo/database": "workspace:*",
"@repo/redis": "workspace:*",
"@repo/types": "workspace:*"
}
}
这种方式的优势是:一次修改,所有引用它的应用都能立即感知,无需发布到 npm。
第八步:启用远程缓存
Turborepo 的远程缓存可以让团队成员和 CI 共享构建结果,大幅提速:
# 登录 Vercel 账户(免费)
npx turbo login
# 链接当前仓库
npx turbo link
在 CI 中设置环境变量:
# GitHub Actions 示例
env:
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: ${{ vars.TURBO_TEAM }}
启用远程缓存后,第一次构建会填充缓存,后续 PR 中未变更的包将直接从缓存恢复,CI 时间可减少 60-80%。
第九步:Docker 本地开发环境
使用 Docker Compose 一键启动 PostgreSQL 和 Redis:
# docker-compose.yml
version: '3.8'
services:
postgres:
image: postgres:16
environment:
POSTGRES_USER: myapp
POSTGRES_PASSWORD: myapp
POSTGRES_DB: myapp
ports:
- "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
redis:
image: redis:7-alpine
ports:
- "6379:6379"
volumes:
- redis_data:/data
volumes:
postgres_data:
redis_data:
开发与构建
启动所有应用:
pnpm dev
构建所有应用:
pnpm build
筛选特定应用(如只构建 backend):
pnpm build --filter=backend
总结与最佳实践
apps/放可部署应用,packages/放共享代码:这是 Turborepo 社区最广泛接受的约定- 根目录只放 repo 级工具:
turbo、husky等,应用的依赖装在各自目录下 - 使用
workspace:*协议引用内部包:pnpm 的原生支持,无需手动同步版本 - 用
^build处理包依赖:确保上游包先构建,下游包再构建 - 尽早启用远程缓存:团队和 CI 都能受益,配置成本极低
这套架构让你能用一套代码管理四种技术栈的应用,同时享受 Drizzle 的类型安全数据库访问、Redis 的高效缓存,以及 Turborepo 带来的构建速度优势。无论是开发还是部署,都能获得顺畅的体验。
文章评论