前端开发
在 Next.js + TypeScript 项目中使用…
适用于需要免 schema、免代码生成、运行时类型安全的 Next.js API 开发。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 38/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 55/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 60/100 ×0.15
适用场景
在 Next.js + TypeScri特定
解决思路
- 确保 TypeScript >= 5.7.2 并开启 strict mode。
- 按结构组织项目:src/pages/_app.tsx 用于 createTRPCNext setup;src/pages/api/trpc/[trpc].ts 作为 tRPC HTTP handler;src/server/routers/_app.ts 主路由;src/server/routers/[feature].ts 功能路由;src/server/context.ts 应用上下文;src/server/trpc.ts procedure helpers;src/utils/trpc.ts 类型安全 React hooks。
- 在 server/trpc.ts 中每个应用只初始化一次 tRPC backend:用 initTRPC.context<Context>().create({ transformer: superjson }) 创建 t,导出 router = t.router、publicProcedure = t.procedure、protectedProcedure = t.procedure.use(isAuthed)、adminProcedure = t.procedure.use(isAdmin)。
- 按功能/域创建 feature routers,每个功能一个路由文件;用 Zod 校验输入,例如 userRouter 中 getById 用 publicProcedure.input(z.object({ id: z.string() })).query(...),update 用 protectedProcedure.input(z.object({ name: z.string().min(1), email: z.string().email() })).mutation(...)。
- 在 server/routers/_app.ts 创建 main app router:导入 router、userRouter、postRouter,导出 appRouter = router({ user: userRouter, post: postRouter }),并导出 type AppRouter = typeof appRouter。
- 在 utils/trpc.ts 配置 tRPC client:使用 httpBatchLink 和 createTRPCNext;导入 superjson 与 type AppRouter;实现 getBaseUrl()(window 存在返回 '',VERCEL_URL 返回 https://${process.env.VERCEL_URL},否则返回 http://localhost:${process.env.PORT ?? 3000});links 使用 httpBatchLink({ url: `${getBaseUrl()}/api/trpc`, maxURLLength: 2083 }),transformer: superjson,ssr: false。
- 对所有 procedure 输入始终使用 Zod 做类型安全和运行时校验,例如 z.object({ email: z.string().email(), age: z.number().min(0).max(120) })。
- 按功能/域组织 routers,不要使用单一巨型 router;每个功能应有自己的 router 文件。
- 实现 middleware 处理认证、日志和横切关注点;例如 isAuthed 中检查 !ctx.user 则 throw new TRPCError({ code: 'UNAUTHORIZED' }),否则 return next({ ctx: { user: ctx.user } })。
- 使用 TRPCError 返回一致且信息明确的错误;例如 throw new TRPCError({ code: 'NOT_FOUND', message: 'User not found' })。
- 使用 SuperJSON 作为数据转换器,自动序列化 dates、Maps、Sets 及其他 JavaScript 类型;在 initTRPC.create({ transformer: superjson }) 中配置。
- 利用 tRPC 内置 React Query 工具做数据获取、mutation 和缓存;查询如 trpc.user.getById.useQuery({ id: '123' });mutation 如 trpc.user.update.useMutation({ onSuccess: () => { utils.user.getById.invalidate(); } });预取如 await utils.user.getById.prefetch({ id: '123' })。
- 在 server/context.ts 创建 context,通过它跨 procedure 共享资源(数据库连接、用户会话等):createContext({ req, res }) 中获取 user,返回 { db: prisma, user, req, res };并导出 type Context = Awaited<ReturnType<typeof createContext>>。
- 只向客户端代码导出类型签名,绝不导出 router 实现;例如只导出 export type AppRouter = typeof appRouter,不要导出实际 router。
- 为不同授权级别创建不同 procedure 类型:publicProcedure = t.procedure;protectedProcedure = t.procedure.use(isAuthed);adminProcedure = t.procedure.use(isAuthed).use(isAdmin)。
- 性能优化:启用 httpBatchLink 请求批处理。
- 性能优化:配置 maxURLLength 防止 URL 长度问题。
- 性能优化:对静态/可预测数据实现 prefetching。
- 性能优化:使用 React Query 的缓存策略。
- 不要使用 any 类型,充分利用 tRPC 的完整类型推断。
- 不要跳过输入校验。
- 不要向客户端暴露内部错误。
- 不要混用服务端和客户端代码。
- 不要创建过大的 router,按功能拆分。
适用边界 · 注意事项
- 项目不使用 TypeScript 严格模式或 TypeScript < 5.7.2 时不要直接套用。
- 不使用 Next.js/React Query/tRPC 技术栈,或只需要简单 REST/GraphQL 时,不必采用。
- 不接受按功能拆分 router、Zod 输入校验或 context/middleware 约定时,不适合采用该模式。