Onlook数据库集成:Supabase与Drizzle ORM配置指南
引言:为什么选择Supabase + Drizzle ORM组合?
在现代Web应用开发中,数据库集成是核心环节。Onlook项目选择了Supabase作为后端即服务(BaaS)平台,配合Drizzle ORM(对象关系映射器)构建了一套高效、类型安全的数据库解决方案。这种组合为开发者提供了:
- 🚀 开箱即用的认证系统
- 🔒 内置的行级安全策略
- 📊 实时数据订阅功能
- 🛡️ 类型安全的数据库操作
- 🔧 强大的迁移工具链
本文将深入解析Onlook项目中Supabase与Drizzle ORM的配置细节,帮助你快速搭建类似的数据库架构。
环境配置与依赖安装
核心依赖包配置
首先,查看项目的package.json文件了解所需依赖:
{
"devDependencies": {
"supabase": "^2.6.8"
}
}
对于Drizzle ORM,项目使用以下核心包:
// 典型依赖配置
{
"dependencies": {
"drizzle-orm": "^0.30.0",
"postgres": "^3.4.4",
"@supabase/supabase-js": "^2.38.0"
},
"devDependencies": {
"drizzle-kit": "^0.20.0"
}
}
Supabase本地开发配置
Onlook使用Supabase的本地开发模式,配置文件位于 apps/backend/supabase/config.toml:
project_id = "onlook-web"
[api]
enabled = true
port = 54321
schemas = ["public", "storage"]
extra_search_path = ["public"]
max_rows = 100
[auth]
site_url = "https://onlook.com"
additional_redirect_urls = [
"http://localhost:3000",
"http://localhost:3000/auth/callback",
]
jwt_expiry = 36000
[db]
port = 54322
[studio]
port = 54323
Drizzle ORM配置详解
数据库连接配置
Drizzle的配置文件 packages/db/drizzle.config.ts 定义了数据库连接和迁移设置:
import { defineConfig } from 'drizzle-kit';
const DEFAULT_DATABASE_URL = 'postgresql://postgres:postgres@127.0.0.1:54322/postgres';
export default defineConfig({
schema: './src/schema',
out: '../../apps/backend/supabase/migrations',
dialect: "postgresql",
schemaFilter: ["public"],
verbose: true,
dbCredentials: {
url: process.env.SUPABASE_DATABASE_URL ?? DEFAULT_DATABASE_URL,
},
entities: {
roles: {
provider: 'supabase'
}
}
});
数据库客户端实现
数据库连接客户端在 packages/db/src/client.ts 中实现:
import * as schema from '@onlook/db/src/schema';
import { drizzle } from 'drizzle-orm/postgres-js';
import postgres from 'postgres';
const globalForDb = globalThis as unknown as {
conn: postgres.Sql | undefined;
};
const conn = globalForDb.conn ?? postgres(process.env.SUPABASE_DATABASE_URL!, { prepare: false });
if (process.env.NODE_ENV !== 'production') globalForDb.conn = conn;
export const db = drizzle(conn, { schema });
export type DrizzleDb = typeof db;
数据模型定义与架构设计
模块化Schema组织
Onlook采用模块化的Schema组织方式:
Supabase认证集成Schema
认证相关的Schema定义在 packages/db/src/schema/supabase/user.ts:
import { jsonb, pgSchema, text, timestamp, uuid } from 'drizzle-orm/pg-core';
export const authSchema = pgSchema('auth');
export const authUsers = authSchema.table('users', {
id: uuid('id').primaryKey(),
email: text('email').notNull(),
emailConfirmedAt: timestamp('email_confirmed_at'),
rawUserMetaData: jsonb('raw_user_meta_data'),
});
export type AuthUser = typeof authUsers.$inferSelect;
数据库种子数据与测试
种子数据配置
项目提供了完整的种子数据配置,位于 packages/db/src/seed/supabase.ts:
import { createClient } from "@supabase/supabase-js";
import { SEED_USER } from "./constants";
export const seedSupabaseUser = async () => {
console.log('Seeding Supabase user...');
if (!process.env.SUPABASE_URL || !process.env.SUPABASE_SERVICE_ROLE_KEY) {
throw new Error('SUPABASE_URL and SUPABASE_SERVICE_ROLE_KEY must be set');
}
const supabase = createClient(process.env.SUPABASE_URL, process.env.SUPABASE_SERVICE_ROLE_KEY);
// 检查用户是否已存在
const { data: { user: existingUser } } = await supabase.auth.admin.getUserById(SEED_USER.ID);
if (existingUser) {
console.log('User already exists, skipping user creation');
return;
}
// 创建测试用户
const { data, error } = await supabase.auth.admin.createUser({
id: SEED_USER.ID,
email: SEED_USER.EMAIL,
password: SEED_USER.PASSWORD,
email_confirm: true,
user_metadata: {
first_name: SEED_USER.FIRST_NAME,
last_name: SEED_USER.LAST_NAME,
display_name: SEED_USER.DISPLAY_NAME,
avatar_url: SEED_USER.AVATAR_URL,
},
});
if (error) {
console.error('Error seeding Supabase user:', error);
throw error;
}
console.log('User seeded!');
};
开发工作流与命令脚本
常用开发命令
项目提供了完整的开发脚本,位于 apps/backend/package.json:
{
"scripts": {
"start": "supabase start",
"stop": "supabase stop",
"push": "supabase db push",
"reset": "supabase db reset",
"db:gen": "supabase gen types --lang=typescript --local --schema public > ../../packages/supabase/src/types/db.ts",
"test": "cd supabase/functions/api && deno test"
}
}
典型开发流程
环境变量配置指南
必需的环境变量
# Supabase配置
SUPABASE_URL=http://localhost:54321
SUPABASE_ANON_KEY=your-anon-key
SUPABASE_SERVICE_ROLE_KEY=your-service-role-key
# 数据库连接
SUPABASE_DATABASE_URL=postgresql://postgres:postgres@127.0.0.1:54322/postgres
# 第三方认证(可选)
GITHUB_CLIENT_ID=env(GITHUB_CLIENT_ID)
GITHUB_SECRET=env(GITHUB_SECRET)
GOOGLE_CLIENT_ID=env(GOOGLE_CLIENT_ID)
GOOGLE_SECRET=env(GOOGLE_SECRET)
环境变量验证策略
在代码中实现环境变量验证:
function validateEnvVars() {
const requiredVars = [
'SUPABASE_URL',
'SUPABASE_ANON_KEY',
'SUPABASE_SERVICE_ROLE_KEY',
'SUPABASE_DATABASE_URL'
];
const missingVars = requiredVars.filter(varName => !process.env[varName]);
if (missingVars.length > 0) {
throw new Error(`缺少必需的环境变量: ${missingVars.join(', ')}`);
}
}
故障排除与最佳实践
常见问题解决方案
| 问题类型 | 症状 | 解决方案 |
|---|---|---|
| 连接超时 | 无法连接到数据库 | 检查Supabase服务状态,验证端口配置 |
| 认证失败 | 401未授权错误 | 验证JWT令牌和环境变量配置 |
| 迁移冲突 | 迁移文件冲突 | 使用supabase db reset重置数据库 |
| 类型错误 | TypeScript编译错误 | 重新生成类型定义npm run db:gen |
性能优化建议
- 连接池管理:在生产环境中配置适当的连接池大小
- 查询优化:使用Drizzle的索引和查询优化功能
- 缓存策略:实现查询结果缓存减少数据库压力
- 监控告警:设置数据库性能监控和告警机制
总结与展望
Onlook项目的Supabase与Drizzle ORM集成展示了一个现代化、类型安全的数据库解决方案。这种架构组合提供了:
- ✅ 开发效率:快速的本地开发和测试环境
- ✅ 类型安全:完整的TypeScript支持
- ✅ 扩展性:模块化的Schema设计
- ✅ 安全性:内置的行级安全和认证机制
- ✅ 可维护性:清晰的迁移和版本控制
通过本文的详细指南,你可以快速在自己的项目中实现类似的数据库架构,享受Supabase和Drizzle ORM带来的开发便利性和生产稳定性。
记住,良好的数据库设计是应用成功的基石。花时间理解这些配置细节,将为你的项目带来长期的技术红利。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



