tRPC + Next.js + Prisma Starter 项目实战指南:基于官方示例快速搭建类型安全全栈应用
【免费下载链接】trpc🧙♀️ Move Fast and Break Nothing. End-to-end typesafe APIs made easy.项目地址: https://gitcode.com/GitHub_Trending/tr/trpc
本文以 tRPC 仓库中 Next.js 示例项目索引文档 starter-projects.md 为主线,系统讲解 tRPC 官方提供的三个可快速启动的样板项目——next-prisma-starter、next-prisma-todomvc与 zART-stack。读完本文,你将掌握如何借助这些 Starter 在几分钟内拉起一套带数据库、E2E 测试、环境变量校验的全栈类型安全应用,并能读懂官方样板背后「Prisma 模型 → tRPC Router → Next.js API Handler → 前端类型化 Hooks」的完整调用链。
一、文档定位与仓库对应关系
该 Starter Projects 页面是 tRPC v9.x 文档中面向 Next.js 用户群的示例索引:它不重复讲解某条 API,而是将「可运行、可复制」的完整示例打包成一张表格,供使用者快速克隆。索引的examples/目录在 tRPC 主仓库内被长期维护(详见 examples/next-prisma-starter 与 examples/next-prisma-todomvc)。
需要注意一点:starter-projects.md属于版本化历史快照,而examples/中的同名项目会随 tRPC 主线持续升级。例如当前 next-prisma-starter/package.json 已使用 Next 15、React 19、Prisma 6 与 tRPC 新版(@trpc/next、@trpc/client等均指向npm:@trpc/*最新 tag),客户端链接也演进为httpBatchStreamLink。因此下文在完整继承文档结论的同时,对代码细节均以仓库当前实际源码为准进行解读。
二、官方提供的三个 Starter 项目一览
下面将文档中的示例索引表完整整理如下(在线演示与外部源码托管地址因不在当前仓库内故不展开链接,可直接在本仓库对应目录查看实现):
| 项目 | 说明 | 技术要点 | 本仓库对应路径 |
|---|---|---|---|
| Next.js Prisma Starter | 集成 Prisma、E2E 测试与 ESLint 的 Next.js 样板 | 全栈类型安全、Cursor 分页、CI、环境变量校验 | examples/next-prisma-starter |
| zART-stack | zero-API + TypeScript + React 的 Monorepo 示例 | 同时包含 React Native、Next.js 与 Prisma | 独立外部仓库(不在本仓库内) |
| Next.js TodoMVC | 基于 SSG 与 Prisma 的 TodoMVC 示例 | 静态生成、经典 Todo 应用 | examples/next-prisma-todomvc |
三者的定位差异明显:next-prisma-starter 是"完整度最高"的工程化样板(含测试、Lint、CI),适合作为真实业务起点;next-prisma-todomvc 是"聚焦型"演示(SSG + 一个经典交互模型),适合学习 Next.js 静态生成与 tRPC 的组合;zART-stack则演示多端复用同一套类型化 API 的 Monorepo 拓扑,适合 React Native 与 Web 共用后端的场景。
三、next-prisma-starter:生产级全栈样板的深度拆解
这是三个 Starter 中最值得精读的一个。官方 README(examples/next-prisma-starter/README.md)将其特性概括为:E2E 类型安全(tRPC)、Next.js 全栈 React、Prisma 数据库、ESLint + Prettier、基于 GitHub Actions 的 CI(Playwright E2E + Lint),以及「在构建/启动时校验环境变量」。
3.1 运行前提与快速启动
该样板对环境的要求只有两点(来自其 README):
- Node.js >= 18.0.0
- 一个可连接的 PostgreSQL 数据库
文档建议通过create-next-app的 example 机制从 tRPC 主仓库的examples/next-prisma-starter路径拉取模板生成新项目。无论以何种方式获得源码,在同一目录内完成安装与启动的命令如下:
pnpm # 安装依赖(postinstall 会自动执行 prisma generate) pnpm dx # 启动本地 Postgres 迁移 + 种子数据 + 开发服务器dx是开发者体验(Developer Experience)命令,通过npm-run-all并行编排,可拆解为两条子命令(见 package.json):dx:next(先migrate-dev再db-seed,随后启动next dev)与dx:prisma-studio(打开 Prisma Studio 可视化查看数据)。
3.2 常用脚本速查表
从 package.json 可以直接获得一套完整的项目脚本语义:
| 脚本 | 执行内容 |
|---|---|
pnpm dev | 等价于dx:next:跑迁移、种子后启动 Next.js 开发服务器 |
pnpm dx | 并行启动 Next.js 开发服务器与 Prisma Studio |
pnpm build | prebuild(prisma generate+prisma migrate)后执行next build |
pnpm start | next start启动生产服务器 |
pnpm db-reset | prisma migrate dev reset重置本地数据库 |
pnpm db-seed | prisma db seed写入种子数据 |
pnpm migrate-dev/pnpm migrate | 开发迁移 / 生产部署迁移 |
pnpm lint | ESLint 检查src目录 |
pnpm test-unit | Vitest 运行单元测试 |
pnpm test-e2e | Playwright 运行端到端测试 |
pnpm test-start | 顺序执行全部单元 + E2E 测试 |
pnpm typecheck | tsc --noEmit静态类型检查 |
值得注意的两个细节:postinstall会自动执行prisma generate,保证新克隆环境首次pnpm后客户端类型即可用;prebuild会在每次正式构建前自动完成迁移,避免「构建成功但数据库结构过期」的经典事故。
3.3 文件结构与关键路径
| 路径 | 职责 |
|---|---|
| prisma/schema.prisma | 数据模型定义(Post 表) |
| prisma/migrations | 迁移记录 |
| src/server/context.ts | 请求级 Context 创建 |
| src/server/trpc.ts | tRPC 服务端初始化(根配置) |
| src/server/env.ts | 环境变量运行时校验 |
| src/server/routers/_app.ts | 根路由聚合与类型导出 |
| src/server/routers/post.ts | 业务 Router 示例(含单元测试) |
| src/pages/api/trpc/[trpc].ts | Next.js 与 tRPC 的 HTTP 桥接层 |
| src/utils/trpc.ts | 客户端类型化 Hooks 工厂 |
| src/utils/transformer.ts | 数据传输序列化器 |
3.4 数据层:Prisma 模型与迁移
数据模型 prisma/schema.prisma 定义了数据源为 PostgreSQL、客户端生成器为prisma-client-js,业务上仅一个Post模型:id(UUID 主键)、title、text、createdAt与updatedAt。源码注释揭示了两条重要设计意图:
createdAt具有唯一性价值,被用作**游标分页(cursor-based pagination)**的排序与游标依据;- 为了让
Date对象经 API 往返后仍保持类型完整,必须引入序列化器(superjson),这正是transformer配置存在的理由。
3.5 环境变量在启动前被强制校验
样板在src/server/env.ts用 zod 定义 schema:DATABASE_URL必须为合法 URL,NODE_ENV必须属于development | test | production,随后用safeParse(process.env)校验——失败即抛错并打印格式化后的错误明细,成功则导出解析后的强类型env。源码注释说明该文件被 Next 配置文件引用,从而做到构建/启动即失败,避免带着错误的数据库地址进入线上。
3.6 Context 的"内外分层"设计
context.ts 实现了 tRPC 官方推荐的拆分模式:
createContextInner(opts):纯数据上下文创建函数,不依赖 Next.js 的 request/response 对象,因此在单元测试、server-side calls 中可以直接调用;createContext(opts: trpcNext.CreateNextContextOptions):HTTP 请求入口,内部直接委托createContextInner。
从源码结构看,这样拆分的好处是让服务端调用(caller)与 HTTP 请求共享同一套上下文装配逻辑,是 tRPC「同一套 Router 可同时服务 HTTP 与进程内调用」能力的基础。
3.7 服务端根配置:初始化一次、按需导出
trpc.ts 是服务端唯一调用initTRPC的位置,并刻意只导出会被使用的工厂函数,从而约束团队只能使用受控的 procedure 基类。其核心配置包括transformer(superjson)与自定义errorFormatter(此处原样透传 shape)。样板还预先导出了router、publicProcedure、mergeRouters、createCallerFactory——当项目需要新增鉴权中间件时,通常就是在此文件扩展出一个protectedProcedure。
3.8 业务 Router:zod 校验 + Cursor 分页 + 错误语义
根路由 _app.ts 聚合了healthcheck与postRouter两个子路由,并导出createCaller(基于createCallerFactory)与AppRouter类型——后者是前后端类型连接的枢纽。
postRouter(post.ts)是理解 tRPC 输入输出约定的最佳范本,包含三种典型形态:
分页列表list:输入用 zod 声明limit(1~100,可空)与cursor(可空字符串)。实现上通过take: limit + 1多取一条判断是否还有下一页,多出的那条被pop()出来作为nextCursor,最终返回items(内部再reverse()保证按createdAt倒序)与nextCursor。这是前端useInfiniteQuery的标准契约格式。
详情查询byId:输入仅id,查询不到时通过throw new TRPCError({ code: 'NOT_FOUND', ... })返回具有业务语义的错误码,而非裸 500——这正是 tRPC 错误体系(见 packages/server 的TRPCError)的典型用法。
创建add:mutation中执行prisma.post.create。注意输入校验使用了.string().uuid().optional()处理可选 UUID,.min(1).max(32)约束标题,从而让非法请求在进入数据库前就被拦截。
所有查询都显式传入defaultPostSelect白名单,只回传明确声明的字段,避免向客户端泄露多余数据。
3.9 HTTP 桥接:Next.js API Handler
src/pages/api/trpc/[trpc].ts 是整个应用的唯一 API 路由文件,通过createNextApiHandler装配appRouter与createContext,并在onError回调中只对INTERNAL_SERVER_ERROR输出日志(便于接入错误上报)。文件末尾以注释形式预留了responseMeta()——当需要基于请求条件设置缓存响应头时(tRPC API Response Caching),在此启用即可。
3.10 客户端:类型化 Hooks 与 baseUrl 解析
src/utils/trpc.ts 通过createTRPCNext<AppRouter, SSRContext>生成强类型 Hooks,客户端配置的要点如下:
getBaseUrl()按运行环境解析服务端地址:浏览器内返回空串,优先读取VERCEL_URL与RENDER_INTERNAL_HOSTNAME等平台变量,最后回落到http://127.0.0.1:PORT,兼容多平台部署;loggerLink仅在开发环境或「下行响应是 Error」时打印日志,避免生产日志噪音;httpBatchStreamLink指向${getBaseUrl()}/api/trpc,实现请求批量合并;其headers()回调在 SSR 场景会把客户端请求头(含 Cookie)转发给服务端——源码注释特别提醒:若运行 Node 18.15 之前版本需剔除connection头;- 顶层
ssr: false关闭服务端渲染数据预取,同时SSRContext类型扩展了 Next 的NextPageContext,允许在需要时通过utils.ssrContext.status = 404干预 HTTP 状态码。
序列化方面,transformer.ts 统一从 superjson 导出transformer,并注释鼓励:若需支持Decimal.js、Temporal等类型,在此扩展后客户端与服务端引用同一实例即可两端生效。
3.11 测试体系:单元 + E2E 双轨
样板对测试的重视体现在两个层面。单元测试层面,Router 目录内直接放置 post.test.ts,配合test-unit(vitest)独立验证业务逻辑,无需启动真实 HTTP 服务。E2E 层面,playwright.config.ts 声明testDir: './playwright'、webServer在 CI 下用npm run start、本地用npm run dev,并设置 CI 重试 3 次与githubreporter 以生成 Actions 注解;smoke.test.ts 给出了两个最小冒烟用例:首页加载后等待text=Starter出现,以及填写表单创建一条随机标题的 Post 并刷新后仍能读到该标题——后一个用例实际上完整验证了「写入数据库 → tRPC 返回 → 页面重新渲染」的闭环。
四、next-prisma-todomvc:SSG 场景的最小闭环演示
第二个可直接在本仓库查看的 Starter 是 TodoMVC 实现(examples/next-prisma-todomvc)。官方文档将其定位为Next.js + SSG + Prisma的经典 Todo 应用。相比上一节的全功能样板,它的价值在于用最小代码量演示静态生成页面如何消费 tRPC 数据。其运行命令为:
pnpm create next-app --example <官方仓库> --example-path examples/next-prisma-todomvc trpc-todo cd trpc-todo && pnpm && pnpm dev(获取源码后,在本仓库examples/next-prisma-todomvc目录执行pnpm && pnpm dev即可本地运行,pnpm dx则同时拉起 Prisma Studio。)
从目录结构看,它保留了与上一节一致的分层习惯:prisma/schema.prisma与prisma/migrations负责数据层,src/server(共 6 个 TypeScript 文件)承载 Router 与 Context,src/utils承载类型化客户端工具,页面侧则加入了过滤路由(src/pages下的 filter 页面)。它同时保留了与 Playwright 的 E2E 测试(test/playwright.test.ts与 playwright.config.ts),并额外附带vercel.json、next.config.js等部署相关配置,便于一键托管到边缘平台。如果你需要理解「SSG 预渲染页面 + 客户端 hydration 后通过 tRPC 取数」的完整节奏,这个 Starter 比全功能样板更易读。
五、zART-stack:跨端 Monorepo 参考
文档索引的第三个示例 zART-stack 是一个独立维护的外部项目,未包含在当前仓库中。其名字是 zero-API + TypeScript + React 的缩写组合,核心亮点是用一个 Monorepo 同时编排 React Native 与 Next.js 两个前端,并共享同一套基于 Prisma 的 tRPC 后端。对于「API 一次定义、多端复用」的诉求,这个示例展示了如何在共享类型边界之上组织 workspace;需要提醒的是,它不在本仓库examples/目录内,若想将其作为业务脚手架,应直接以文档所列方式克隆其独立源码仓库使用。
六、如何基于 Starter 开启你自己的项目
结合三个示例的源码,落地一个全新项目时的推荐动作如下:
- 决定骨架:追求工程完整度选
next-prisma-starter(examples/next-prisma-starter);想先跑通最小闭环再看 SSG 选next-prisma-todomvc(examples/next-prisma-todomvc);需要多端复用再参考 zART-stack 的 Monorepo 拓扑。 - 改造数据层:编辑
prisma/schema.prisma扩展业务模型,然后执行prisma migrate dev生成迁移——两个 Starter 都内置了迁移目录作为起点。 - 扩展 Router:仿照 post.ts,在
src/server/routers下新增业务 Router,并在根路由 _app.ts 中聚合;同一套代码即可被 HTTP 与createCaller双通道复用。 - 保持客户端同步:新增过程后无需手写任何请求层代码——
src/utils/trpc.ts中的类型化 Hooks 会随AppRouter类型自动推导出新过程的入参与出参。 - 补测试与校验:沿 post.test.ts 的思路补 Router 单测,沿 smoke.test.ts 的「表单创建→刷新断言」模式补关键路径的 E2E 用例,并在
src/server/env.ts中为每个新增环境变量加上 zod 约束。
七、小结
官方 Starter Projects 索引(starter-projects.md)提供了三个不同粒度的起点:next-prisma-starter把「类型安全、分页、迁移、环境变量校验、单测与 E2E」完整集成到一个 Next.js 应用中,是最值得作为生产基座的参考实现;next-prisma-todomvc以最小代码量阐释 SSG 与 Prisma 的组合;zART-stack 则打开了多端复用的视野。结合 examples/next-prisma-starter 目录下的真实源码逐文件对照阅读,你不仅能快速搭建应用,更能理解 tRPC 全栈类型安全从模型定义、Router 声明到前端 Hooks 是如何一环扣一环地传递下去的。
【免费下载链接】trpc🧙♀️ Move Fast and Break Nothing. End-to-end typesafe APIs made easy.项目地址: https://gitcode.com/GitHub_Trending/tr/trpc
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考