ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

T3 Stack全栈开发实战:Next.js + TypeScript + tRPC + Prisma 类型安全一体化

T3 Stack全栈开发实战:Next.js + TypeScript + tRPC + Prisma 类型安全一体化 1. 从零搭建t3code一个基于T3 Stack的全栈项目实践记录我平时喜欢在 GitHub 上刷各类全栈项目看到 t3code 这个名字第一反应就是 T3 Stack——TypeScript、Tailwind CSS、tRPC 三件套加上 Next.js 的那套组合拳。这套技术栈在圈子里讨论度一直很高但很多人只是看了文档没真正上手跑过完整项目。这篇文章就用 t3code 这个实际项目把我从初始化到部署的全过程、踩过的坑、还有对每个关键技术选型的思考一次性讲清楚。如果你是刚接触全栈开发、想在 2025 年找一套能快速落地且类型安全的前后端一体化方案的人这篇内容可以直接帮你省掉一个月的摸索时间。先说结论t3code 本质上不是某个公司出的框架而是社区里对 T3 Stack 实践项目的统一叫法也可以是你在本地随手建的一个实验仓库名。我这次把它做成一个带认证、数据库、API 路由和前端页面的完整示例项目技术栈锁定 Next.js 14 TypeScript Tailwind CSS tRPC Prisma SQLite跑通从数据库到 UI 的完整数据流。下面所有内容都来自我实际敲过的命令和改过的代码没水分。2. 为什么选 T3 Stack一次讲清楚这套技术组合的底层逻辑2.1 T3 Stack 到底是什么解决什么问题T3 Stack 是 tRPC 作者 Theo 带起来的一套全栈开发方案核心成员是 Next.js、TypeScript、Tailwind CSS、tRPC通常还会配上 Prisma 和 NextAuth.js。它不是一个新的框架而是把几个各自独立且优秀的工具组合成一个默认最佳实践。很多人在选型时会纠结前端用 React/Vue后端用 NestJS/Express数据库用 MySQL/PostgreSQL然后再写一堆 REST API 或者 GraphQL 的 schema。问题在于这套组合到了联调阶段前端拿到接口文档后端按文档返回数据中间一旦字段类型对不上、参数名改了没同步就会出各种 ghost bug。你半夜调接口看到 undefined 报错一层层往上翻最后发现是后端字段拼错了这种体验我相信大家都经历过。T3 Stack 的思路是既然前后端都用 TypeScript那就让类型直接贯穿整个调用链从数据库模型到后端路由再到前端调用全部自动推导。数据库表结构用 Prisma 定义tRPC 的 router 直接返回 Prisma 的查询结果前端调用时不需要手写任何 interface 或类型声明类型是跟着接口走的。数据模型一旦改了编译期就能暴露所有调用方的错误而不是等到运行时候才爆雷。这个价值在单人全栈开发时感受最明显因为一个人同时写前端和后端最大的痛苦是脑子里要维护两套类型定义。我现在把 t3code 这个项目的运行流程拆开浏览器请求一个页面 - Next.js 服务端渲染时发起 tRPC 调用 - tRPC 执行 query 函数 - Prisma 查 SQLite - 数据原路返回并自动带上完整类型。中间没有任何手工的类型断言所有校验都在编译期完成。2.2 为什么选 Next.js 而不是 Vite Express很多人问过我这个组合能不能换成 Vite 前端加 Express 后端答案是能但那会丢掉 T3 Stack 最大的优势前后端一体化的开发体验与部署模型。Next.js 提供了文件系统路由、服务端组件、API 路由、中间件这些能力让 tRPC 可以直接挂在 Next.js 的 API 路由上运行而不需要单独开一个后端服务。在 t3code 这个项目里tRPC 的请求和普通的 API 请求一样走/api/trpc这个路径但在代码层面前端调用时是一个完全类型安全的函数不是 URL 拼接。这带来的实际好处部署时可以只部署一个服务不需要考虑前后端分离的跨域方案不需要在 nginx 里配一堆代理规则不需要维护两套环境的 CORS 配置。我本地起一个next dev前端后端都在了。生产环境用next build next start也只有一个服务。这个心智负担的降低对于小团队和个人项目来说是决定性的。Vite 加 Express 的方案适合你本身就要拆分成独立前后端服务的场景比如前端要独立部署到 CDN、后端要弹性扩容或者前后端团队是不同的人维护。但如果你和我一样是单兵作战或者小团队快速验证T3 Stack 的一体化模型会大大提高交付速度。2.3 类型安全在 t3code 里具体是怎么闭环的我来画一个实际的数据流帮大家直观感受这套类型安全机制。在 t3code 里我定义了一个帖子表model Post { id String id default(cuid()) title String content String published Boolean default(false) createdAt DateTime default(now()) authorId String author User relation(fields: [authorId], references: [id]) }Prisma 会基于这个 model 自动生成完整的 TypeScript 类型包含Post、PostCreateInput、PostWhereUniqueInput这些。然后我在 tRPC router 里写一个 query// server/api/routers/post.ts import { z } from zod; import { createTRPCRouter, publicProcedure } from ~/server/api/trpc; export const postRouter createTRPCRouter({ getAll: publicProcedure.query(async ({ ctx }) { return ctx.db.post.findMany({ include: { author: true }, orderBy: { createdAt: desc }, }); }), create: publicProcedure .input(z.object({ title: z.string().min(1), content: z.string() })) .mutation(async ({ ctx, input }) { return ctx.db.post.create({ data: { title: input.title, content: input.content, authorId: ctx.session?.user?.id ?? anonymous, }, }); }), });前端调用时的体验是这样的import { api } from ~/trpc/react; // 在客户端组件里调用 const { data: posts, refetch } api.post.getAll.useQuery(); // 新增帖子 const createPost api.post.create.useMutation({ onSuccess: () refetch(), });整个过程里posts的类型自动就是 Prisma 里findMany返回的完整结构加上author的嵌套信息。如果哪天我改了 Prisma 的 model比如给 Post 加一个views字段那么重新运行prisma generate后前端代码里posts的类型立刻会带上views不需要手动同步任何 interface。这套机制让我在 t3code 项目里删掉了几乎所有的interface Props和type ApiResponse声明文件。以前写 CRUD 项目光是对接口类型就要写几百行现在这些全自动了。省下的时间不是一星半点尤其是后续重构的时候你改数据库、改 router编译器会告诉你哪些调用方要跟着改杜绝了线上才发现的运行时错误。3. t3code 实操初始化、配置与核心代码细节3.1 环境准备与脚手架初始化我不建议从零手动去搭 Next.js 项目再慢慢装 tRPC社区已经提供了创建 T3 Stack 项目的脚手架一条命令搞定npx create-t3-applatest t3code执行后脚手架会问你要装哪些模块我的选择供参考Next.js 版本14App RouterTypeScript是Tailwind CSS是tRPC是Prisma是NextAuth.js是数据库SQLite本地开发不折腾这里特别提醒一句脚手架默认会让你选数据库如果选了 SQLite后面 Prisma 的配置会自动指向本地文件零成本起步。如果一开始就选 PostgreSQL本地还得额外起容器或者安装服务对纯前端想快速验证的人来说门槛就高了。我的建议是初始先用 SQLite 跑通流程项目上线或者数据量大了再迁移到 PostgreSQLPrisma 的 schema 基本不用改只需要改 datasource 里的连接串。3.2 目录结构与关键文件解析脚手架生成的项目结构在 App Router 模式下非常清晰但有些细节新手容易迷路t3code/ ├── prisma/ │ └── schema.prisma # 数据库模型定义 ├── src/ │ ├── app/ │ │ ├── api/ │ │ │ └── trpc/ │ │ │ └── [trpc]/ │ │ │ └── route.ts # tRPC 的 HTTP 入口 │ │ ├── layout.tsx │ │ ├── page.tsx # 首页 │ │ └── _trpc/ │ │ └── Provider.tsx # tRPC 客户端 Provider │ ├── server/ │ │ ├── api/ │ │ │ ├── routers/ │ │ │ │ ├── post.ts # 帖子相关路由 │ │ │ │ └── root.ts # 路由聚合 │ │ │ └── trpc.ts # tRPC 初始化与上下文 │ │ └── auth.ts # NextAuth 配置 │ ├── trpc/ │ │ ├── client.ts # 客户端 tRPC 辅助函数 │ │ ├── react.tsx # React Hooks 封装 │ │ └── server.ts # 服务端 tRPC 调用 │ └── styles/ │ └── globals.css └── package.json最容易搞混的是src/server/api/trpc.ts和src/trpc/client.ts这两个文件。前者定义的是服务端的createTRPCRouter、publicProcedure这些基础对象包含 Context 的构建逻辑后者是给 React 前端用的客户端 wrapper把 tRPC 的 hooks 和 types 都导出来。两者一个管后端能力一个管前端调用分工明确但名字相近。3.3 核心链路实现从数据库到 UI 的完整数据流我拿 t3code 里最核心的发帖展示帖列表功能来走一遍完整链路这也是多数学习者的第一个需求。第一步定义 Prisma Model刚才已经给出了 Post 的模型定义这里注意authorId关联到了User但初始 schema 里可能没有 User 表因为 NextAuth 默认会带一个 Account/Session/User 的模型。如果你没有选 NextAuth需要自己补一个简单的 User 模型否则 Post 的 relation 会报错。我这次选的就是带 NextAuth所以 User、Account、Session 三张表现在已经存在。第二步在 tRPC router 里注册 query回到刚才的 post router 代码。publicProcedure表示这个接口不需要登录就能访问。如果要加权限控制用protectedProcedure它内部会先校验 session没有登录直接抛 UNAUTHORIZED 错误前端 hooks 会把这个错误映射成 APIError 对象在 onError 回调里统一处理跳转登录页体验很好。第三步暴露 router 到根路由root.ts的作用是聚合所有子 router// src/server/api/root.ts import { postRouter } from ~/server/api/routers/post; import { createTRPCRouter } from ~/server/api/trpc; export const appRouter createTRPCRouter({ post: postRouter, }); export type AppRouter typeof appRouter;这个AppRouter类型是整个类型安全的枢纽。客户端手写代码时不需要 import 这个类型api.post.getAll这种链式调用的类型都是从AppRouter自动推导出来的。第四步HTTP 入口让请求到达 tRPC脚手架已经生成好src/app/api/trpc/[trpc]/route.ts它的作用是把所有发往/api/trpc/*的请求转发给 tRPC 处理器。这就是为什么前端没有任何 URL 字符串也能调用后端因为 tRPC 客户端在初始化时已经知道了 endpoint// src/trpc/react.tsx export const api createTRPCReactAppRouter(); // Provider 里配置了 links默认 endpoint 是 /api/trpc第五步前端页面调用在page.tsx里使用服务端组件模式下怎么调 tRPC这里有个容易踩的坑直接用api.post.getAll.useQuery()是客户端 hooks 的用法不能在服务端组件里用。服务端组件需要api.post.getAll.fetch()这种直接调用形式。我的实际代码// 服务端组件里获取数据 import { api } from ~/trpc/server; export default async function HomePage() { const posts await api.post.getAll.fetch(); // posts 的类型自动推导为带 author 的完整数组 return ( div classNamespace-y-4 {posts.map((post) ( div key{post.id} classNamerounded-lg border p-4 h2 classNametext-lg font-bold{post.title}/h2 p classNamemt-2 text-gray-600{post.content}/p span classNametext-sm text-gray-400 by {post.author.name ?? 匿名用户} /span /div ))} /div ); }注意api.post.getAll.fetch()的形参和返回值类型完全和服务端 query 的定义对齐posts的每一项都有id、title、content、published、createdAt、authorId以及嵌套的author编译器会强制你正确处理这些字段妈妈再也不用担心我把post.author写成post.user。第六步写操作与自动刷新页面上的表单提交用 mutationuse client; import { api } from ~/trpc/react; export function CreatePostForm() { const utils api.useUtils(); const createPost api.post.create.useMutation({ onSuccess: () { utils.post.getAll.invalidate(); // 让 getList 自动重新拉取 }, }); return ( form onSubmit{(e) { e.preventDefault(); const formData new FormData(e.currentTarget); createPost.mutate({ title: String(formData.get(title)), content: String(formData.get(content)), }); }} input nametitle placeholder标题 classNameborder p-2 / textarea namecontent placeholder内容 classNameborder p-2 / button typesubmit classNamebg-blue-500 px-4 py-2 text-white 发布 /button /form ); }这里最有价值的是utils.post.getAll.invalidate()。以前写前端发布完新数据要手动改本地 state 或者重新 fetch。现在一行代码tRPC 会递归标记跟post.getAll相关的缓存为过期下一次渲染会自动重新请求。这种按需失效的缓存策略比 React Query 默认的全量失效要精准得多性能开销也更小。3.4 认证集成NextAuth.js 的坑与配置细节t3code 项目里如果要加登录功能脚手架已经集成好了 NextAuth.js但默认配置里你要自己填AUTH_SECRET环境变量否则启动时一堆红色警告。我的 .env 文件DATABASE_URLfile:./db.sqlite AUTH_SECRET这里粘贴你生成的密钥密钥生成命令openssl rand -base64 32NextAuth 配置里的 session 策略要选jwt因为 tRPC 的 Context 里需要同步 session 信息。还有 Prisma adapter 的配置主要是管理 Account/Session/User 三张表和 NextAuth 之间的映射。在src/server/auth.ts里配置了 providers 后tRPC Context 就可以拿到当前用户// src/server/api/trpc.ts export const createTRPCContext async (opts: { headers: Headers }) { const session await getServerAuthSession(); return { db, session, ...opts, }; };这样在protectedProcedure里就能直接拿到ctx.session.user.id做数据隔离或者权限判断都很方便。我实测下来GitHub Provider 登录的流程最顺畅只需要在 GitHub OAuth App 里设置http://localhost:3000/api/auth/callback/github这个回调地址就行。微信、Google 一些 Provider 在本地经常遇到重定向跳转问题排查起来很费劲新手建议先用 GitHub 或者干脆直接邮箱验证码别把时间浪费在 Provider 配置上。4. t3code 实际操作中遇到的问题与排查方法4.1 tRPC 请求 404检查 API 路由入口这是我在本地一启动就遇到的第一个问题。页面正常渲染但所有 tRPC 调用都是 404。后来发现原因是App Router 版本的 create-t3-app 默认把 tRPC 入口放在/api/trpc/[trpc]/route.ts但如果你的 Next.js 版本是 Page Router 结构pages 目录入口文件路径完全不一样。记住一个检查方法浏览器直接访问http://localhost:3000/api/trpc/pingReact Query 的调用本质是一个 HTTP GET 请求如果入口配置正确这里应当返回一个 JSON 结构里面会包含错误信息或者正常数据。如果返回 404说明路由入口文件路径不对或者你在自建项目时漏掉了route.ts的导出。4.2 Prisma 初始化报错表不存在先跑 migrate另一个常见问题prisma generate生成了 client但运行时查询报Table Post doesnt exist。这是因为 Prisma model 只是定义还没有映射到数据库表。需要在项目根目录执行npx prisma migrate dev --name init这个命令会根据 schema.prisma 自动生成迁移文件并同步数据库结构。如果用的是 SQLite生成的数据库文件就在prisma/dev.db位置你可以在 Prisma Studio 里可视化查看npx prisma studio浏览器打开http://localhost:5555就能看到所有表的记录改数据很方便比命令行一条条查快多了。还有个小坑schema.prisma 里的datasource块默认用的 provider 是sqliteurl env(DATABASE_URL)指向file:./db.sqlite。但不同版本的连接字符串格式有细微差别如果你用的是本地文件路径不要加?connection_limit1这种连接池参数sqlite 不支持会直接导致连不上。4.3 React Query 的 type error别忘了给 useQuery 传参新手在客户端组件里写api.post.getById.useQuery()没传 ID然后发现类型报错找不到useQuery的重载。其实不是 tRPC 的问题是 getById 这个 procedure 需要一个 input你可以在 useQuery 里传{ id: xxx }也可以把 input 置为undefined——但基于 tRPC 的类型安全如果 query 需要 input 而你传了 undefined类型层面会警告。最好的实践是在后端 router 定义时将 input 设为可选或者统一用required: false的 zod schema。我的实际做法是需要列表页和详情页都查询同一个字段时用getAll查列表单独再写一个getById接受可选参数内部判断。4.4 Tailwind CSS 样式不生效create-t3-app 的 Tailwind 已经预配置好了但如果你中途升级或自己添加 PostCSS 插件容易出现样式全部丢失的情况。检查tailwind.config.ts里的content数组是否包含了所有需要扫描的目录典型的配置是content: [./src/**/*.{js,ts,jsx,tsx}],漏掉新加的页面目录对应的类名就不会被编译。另外如果你用了 CSS 变量覆盖主题色注意:root变量在 globals.css 里要在tailwind base之前声明否则会被 preflight 覆盖掉。4.5 常见问题速查表现象可能原因排查路径tRPC 请求 404入口文件路径错误或未导出浏览器直连/api/trpc/xxx检查 JSON 响应Prisma 查询报表不存在未执行 migrate执行npx prisma migrate devNextAuth 登录后 session 为空session 策略或数据库 adapter 配置错误查服务端日志与 consoleTailwind 类名不生效content 扫描范围未覆盖检查 tailwind.config.ts content 路径部署后 tRPC 报 CORS前后端分离部署但未配跨域将前后端部署在同一服务或域名下第 5 条特别说明一下T3 Stack 的一体化部署意味着你不应该把 Next.js 和 API 拆开跨域部署。如果你确实需要独立部署前端静态资源那就需要给 API 路由单独配 CORS 中间件建议直接用 Next.js 中间件函数加响应头来实现不要图省事在组件里乱设 Access-Control-Allow-Origin。5. t3code 中 Prisma 数据建模与迁移实战5.1 从业务需求到数据模型我在 t3code 里不止做了帖子功能还加了标签系统和评论功能。这里我想重点讲一下数据建模的思考过程因为大多数人知道怎么写 Prisma schema但面对一个实际业务需求时容易纠结要不要建关联表用枚举还是字符串字段要不要加默认值我的标签和帖子是多对多关系Prisma 里直接用隐式多对多就够用model Tag { id String id default(cuid()) name String unique posts Post[] } model Post { ... tags Tag[] }Prisma 会自动创建一张名为_PostToTag的关系表不需要你手动管理。如果后续这张隐式关联表需要存额外字段比如职位、权重那就需要把它显式拆出来变成独立模型。我的判断标准很简单只需要知道哪些帖子挂哪些标签用隐式需要在关联本身存业务信息比如谁给这个帖子打了标签用显式。数据库索引方面如果帖子列表经常按createdAt排序就在 Post 模型里加index([createdAt])否则数据量大了之后一页一页翻列表全表扫描会越来越慢。Prisma 对 SQLite 和 PostgreSQL 的索引语法通用养成顺手加索引的习惯后面省大量接口调优的功夫。5.2 迁移流程的正确打开方式在 t3code 里我经历了三次结构调整每次都是同一个流程改prisma/schema.prisma运行npx prisma migrate dev --name description运行npx prisma generatemigrate dev会生成 SQL 迁移文件到prisma/migrations/目录同时自动执行迁移。这一步如果出现生产库和本地库的 schema 不一致就会报警告。我建议本地开发时多建几个分支或环境独立的数据库每条迁移记录保持可回溯的状态。有个注意事项migrate dev会触发prisma generate然后你的 TypeScript 类型会自动更新不需要每次手动跑 generate。但如果你的 IDE 里 TS Server 一直报旧类型错误可以重启一次 TS Server这是最常见的一个环境卡点。5.3 种子数据怎么设计开发阶段没有数据页面空空荡荡前端列表样式全部白调。我会在prisma/seed.ts里写一个播种脚本import { PrismaClient } from prisma/client; const prisma new PrismaClient(); async function main() { const user await prisma.user.create({ data: { name: demo_user, email: demoexample.com, }, }); await prisma.post.createMany({ data: [ { title: 第一篇帖子, content: 用 t3code 搭建的第一个内容, authorId: user.id, published: true, }, ... ], }); } main().finally(() prisma.$disconnect());然后 package.json 里配置prisma: { seed: tsx prisma/seed.ts }以后任何时候想要干净的数据环境跑一下npx prisma db seed就能重建基础数据。分享一个小技巧种子脚本里用deleteMany清空老数据时如果外键约束冲突执行顺序要颠倒一下先删子表再删父表。SQLite 默认不强制外键但 PostgreSQL 会严格检查写种子脚本时养成反序删除的习惯更稳。6. t3code 项目优化与部署实战6.1 包体积分析与 tree-shakingNext.js 14 默认有很好的 tree-shaking 能力但 tRPC 的服务端代码和客户端代码混在同一个项目里打包时略有不注意就会把 Prisma Client 全部打进前端 bundle。我实际检查过next build的产物报告发现只要在客户端组件里不小心导入了服务端的db或appRouterPrisma 就会被拉到浏览器 bundle体积直接暴涨几 MB。检查方法ANALYZEtrue next build这需要你安装next/bundle-analyzer。然后逐个看 chunk 大小凡是包含prisma、prisma/client的 chunk 都要警惕。正常情况 Prisma 只应该在服务端 bundle 出现。另外尽量不在_trpc/Provider.tsx这种顶层组件里 import 额外的内容。tRPC 客户端 wrapper 保持精简除了createTRPCReact、httpBatchLink这些必要依赖外不再放别的业务逻辑否则所有页面都会背着这部分负担。6.2 缓存策略怎么让 tRPC 复用数据而不是每次刷新都打接口React Query 的缓存机制默认对 GET 请求是生效的staleTime 默认为 0意味着每次进入页面都会重新请求但如果你希望列表 30 秒内不重复拉接口可以在 Provider 里统一配置// src/trpc/react.tsx return ( api.Provider client{trpcClient} queryClient{new QueryClient({ defaultOptions: { queries: { staleTime: 30 * 1000, refetchOnWindowFocus: false, }, }, })} {children} /api.Provider );refetchOnWindowFocus默认是 true频繁在窗口之间切换会导致接口请求风暴。我一般开发环境开着方便看实时数据生产环境直接关掉。staleTime设得越长服务器压力越小但数据新鲜度越低要根据业务类型权衡。比如帖子列表 30 秒刷新一次可以接受用户余额这种请求就别缓存了。6.3 部署到 Vercel 的完整配置T3 Stack 项目部署到 Vercel 非常顺手但有几个必须注意的点。先在 Vercel 后台的 Project Settings 里配置环境变量把.env里的DATABASE_URL和AUTH_SECRET抄过去注意生产环境别用 SQLite 文件因为 Vercel 的无服务器环境没有持久磁盘文件会被重置。我的建议是生产环境直接上 Vercel Postgres 或者 Neon 的免费 PostgreSQL 实例把连接串换一下即可。DATABASE_URLpostgresql://user:passwordyour-neon-host/t3code?sslmoderequire然后确保 rebuild 脚本包含 migration 步骤。我平时用npx prisma migrate deploy next buildmigrate deploy会执行所有未执行的迁移文件但不会修改 schema所以它比migrate dev更适合生产环境。本地加字段可以随便跑 dev但生产环境没有交互提示deploy 才是安全操作。Vercel 的部署流程我实测下来只需要 3 分钟Git 推送之后 Vercel 自动识别 Next.js 项目执行 build 命令完成后自动分配一个 URL。唯一想吐槽的是国内访问 Vercel 有时不够稳如果你主要面向国内用户那就要备选其他平台了。6.4 Docker 部署把 t3code 装进容器如果你的项目需要自己控制服务器Docker 部署是更主流的选择。我为 t3code 写了一个极简 DockerfileFROM node:20-alpine AS base WORKDIR /app FROM base AS deps COPY package.json pnpm-lock.yaml* ./ RUN corepack enable pnpm install --frozen-lockfile FROM base AS builder COPY --fromdeps /app/node_modules ./node_modules COPY . . RUN npx prisma generate pnpm build FROM base AS runner RUN addgroup --system --gid 1001 nodejs adduser --system --uid 1001 nextjs COPY --frombuilder /app/public ./public COPY --frombuilder --chownnextjs:nodejs /app/.next ./.next COPY --frombuilder /app/node_modules ./node_modules USER nextjs EXPOSE 3000 CMD [pnpm, start]注意 Prisma 在容器构建阶段必须执行prisma generate否则运行时的 Prisma Client 缺少查询引擎会直接报错。此外容器里如果用 SQLite要把数据库文件放到持久化卷否则容器重启就清空。这里要特别说明的是 Dockerfile 这种多阶段构建虽然看起来多写了几个 COPY但每一层都有它的用途deps阶段只装依赖作为构建缓存builder阶段做完整构建runner阶段尽量精简只保留运行必需的文件。这样镜像体积可以控制在 300MB 以内而如果不分层地直接把 node_modules 扔进去每次构建都要重装依赖体积可能轻松超过 1GB。7. 我的实操心得t3code 项目带给我的四个改变写了这么多把最实际的感受和总结放在最后这也是我在整个过程中踩坑后得出的经验。第一类型安全不是束缚是最大提速引擎。t3code 开发后期我经常一次性改掉七八个文件的代码因为有编译器兜底我敢大胆重构。以前写后端接口改一个字段名要全局搜索替换现在改完 Prisma model所有引用点暴露出红色波浪线跟着修完基本不会漏。第二别让工具链反过来主导你的业务设计。T3 Stack 的脚手架虽然方便但默认的全家桶不是所有项目都需要。如果你只是一个简单博客不需要 tRPC直接用 Next.js 的 RSC 或者 API route 就够了。t3code 这个项目之所以适合用全套 T3 Stack是因为它核心特性就是类型安全的 CRUD 交互tRPC 的收益才最大。第三数据库选型别从入门就上分布式数据库。本地开发 SQLite云端用 PostgreSQL这个组合在 T3 Stack 生态里是最平滑的。你想要多租户、实时订阅这些能力应该是在业务真正需要时再引入而不是一开始抱着完美主义心态上重型装备。第四多参考社区真实的 T3 Stack 项目而不是官方文档。官方文档偏 API 说明缺少实际业务的整合。我在做 t3code 时参考了不少开源项目看它们如何处理认证、权限、文件上传、错误边界收获比单纯读文档大得多。如果你也想找一个合适的项目练手直接搜 GitHub 上create-t3-app相关的高星仓库克隆下来改一改比从零写更有感觉。
返回列表