常见任务和故障排除
本指南涵盖常见的开发任务和问题解决方案。
1. 创建新的 tRPC 路由
Section titled “1. 创建新的 tRPC 路由”步骤:
- 在
packages/api/src/routers/创建新文件:
import { z } from 'zod'import { publicProcedure, router } from '../index'
export const postsRouter = router({ list: publicProcedure.query(async () => { // 实现逻辑 })})- 在
packages/api/src/routers/index.ts中注册:
import { postsRouter } from './posts'
export const appRouter = router({ posts: postsRouter // ... 其他路由})- 在前端使用:
const { data } = trpc.posts.list.useQuery()2. 添加数据库表
Section titled “2. 添加数据库表”步骤:
- 在
packages/db/src/schema/定义新表:
import { pgTable, text, timestamp } from 'drizzle-orm/pg-core'
export const posts = pgTable('posts', { id: text('id').primaryKey(), title: text('title').notNull(), content: text('content'), createdAt: timestamp('created_at').defaultNow()})- 在
packages/db/src/schema/index.ts导出:
export * from './posts'- 运行
pnpm run db:push应用变更
3. 创建前端组件
Section titled “3. 创建前端组件”步骤:
- 在
apps/web/src/components/创建组件:
import { trpc } from "@/utils/trpc";
export function PostList() { const { data } = trpc.posts.list.useQuery();
return ( <div> {data?.map(post => ( <div key={post.id}>{post.title}</div> ))} </div> );}- 在页面中使用:
import { PostList } from "@/components/PostList";
export default function Page() { return <PostList />;}问题: TypeScript 类型检查失败
解决方案:
# 检查所有类型pnpm run check-types
# 检查特定包cd packages/api && pnpm run check-types常见原因:
- 缺少类型定义
- 导入路径错误
- 环境变量类型不匹配
问题: 数据库连接或查询失败
解决方案:
# 打开数据库管理界面pnpm run db:studio
# 检查数据库连接# 验证 DATABASE_URL 环境变量常见原因:
- 数据库未启动
- 连接字符串错误
- 表不存在(需要运行迁移)
环境变量问题
Section titled “环境变量问题”问题: 环境变量未正确加载
解决方案:
- 检查
.env文件是否存在 - 验证
packages/env/src/server.ts中的配置 - 确保环境变量在
turbo.json中声明
常见原因:
.env文件未创建- 环境变量名称拼写错误
- 类型验证失败
问题: 用户无法登录或会话丢失
解决方案:
- 检查
BETTER_AUTH_SECRET是否正确设置 - 验证
BETTER_AUTH_URL和CORS_ORIGIN配置 - 检查浏览器 Cookie 设置
常见原因:
- Cookie 被阻止
- CORS 配置错误
- 认证密钥不匹配
OIDC 流程走不通
Section titled “OIDC 流程走不通”问题: 在普通 Chrome 中走 OIDC 授权流程时失败(无痕模式正常)
这通常是因为浏览器残留了旧的 Cookie、Draft Mode 状态或 Vercel Toolbar 注入的参数,干扰了正常的重定向链。按以下步骤逐一排查:
1. 清除 IAM 站点数据
需要分别清除前端和后端两个站点的数据:
- 打开
chrome://settings/content/all - 搜索
iam-nodejs-web.vercel.app,点进去 → 删除数据 - 搜索
iam-nodejs-server.vercel.app,点进去 → 删除数据
更快的方法:分别打开两个站点的任意页面,点击地址栏左侧的”网站信息”图标 → 网站设置 → 删除数据。
2. 关闭 Vercel Toolbar
如果请求参数中出现了 __vercel_toolbar=1,说明 Vercel Toolbar 处于激活状态:
- 在页面右下角找到 Vercel Toolbar 并关闭
- 如果关闭后请求中仍然带有该参数,打开 DevTools → Application → Cookies,手动删除
__vercel_toolbarCookie
3. 退出 Draft Mode / Preview 状态
如果请求头中出现 x-vercel-draft-status: 1,说明页面处于 Draft/Preview 模式:
- 打开站点首页,寻找”Exit Draft Mode”入口并点击退出
- 如果找不到该入口,打开 DevTools → Application → Cookies,删除该站点的所有 Cookie,然后刷新页面
4. 关闭所有旧标签页
关闭所有与 OIDC 流程相关的标签页,包括:
/oauth-login登录页/consent授权确认页- OIDC Debugger 页面
- 任何其他残留的测试页面
5. 从头发起新的 OIDC 流程
新开一个标签页,从第三方客户端重新发起完整的 OIDC 授权流程。不要从浏览器历史记录中恢复、刷新旧页面或使用后退按钮继续之前的流程。
问题: 构建失败或找不到模块
解决方案:
# 清理并重新安装rm -rf node_modulespnpm install
# 清理构建缓存pnpm run build --force常见原因:
- 依赖未正确安装
- workspace 依赖未构建
- 缓存问题
1. 使用 Turborepo 缓存
Section titled “1. 使用 Turborepo 缓存”Turborepo 自动缓存构建结果:
- 只重新构建变更的包
- 加速 CI/CD 流程
- 减少构建时间
2. 数据库查询优化
Section titled “2. 数据库查询优化”使用索引:
import { index } from 'drizzle-orm/pg-core'
export const posts = pgTable( 'posts', { id: text('id').primaryKey(), authorId: text('author_id') }, (table) => ({ authorIdIdx: index('author_id_idx').on(table.authorId) }))避免 N+1 查询:
// 不好 - N+1 查询const posts = await db.select().from(posts)for (const post of posts) { const author = await db.select().from(user).where(eq(user.id, post.authorId))}
// 好 - 使用 joinconst postsWithAuthors = await db.select().from(posts).innerJoin(user, eq(posts.authorId, user.id))3. 前端优化
Section titled “3. 前端优化”使用 React Query 缓存:
const { data } = trpc.posts.list.useQuery(undefined, { staleTime: 5 * 60 * 1000, // 5 分钟 cacheTime: 10 * 60 * 1000 // 10 分钟})代码分割:
// 动态导入const HeavyComponent = dynamic(() => import("./HeavyComponent"), { loading: () => <div>Loading...</div>,});4. API 优化
Section titled “4. API 优化”批量操作:
// 批量查询const items = await db.select().from(items).where(inArray(items.id, ids))分页:
const posts = await db .select() .from(posts) .limit(pageSize) .offset(page * pageSize)- 代码组织: 保持代码模块化和可维护
- 类型安全: 充分利用 TypeScript 类型系统
- 错误处理: 提供清晰的错误消息
- 测试: 编写单元测试和集成测试
- 文档: 保持文档更新
如果遇到问题:
- 检查相关指南文档
- 查看项目 README
- 搜索 GitHub Issues
- 联系开发团队