基于T3 Stack的代码片段管理工具t3code开发实践

发布时间:2026/10/28 6:29:52
基于T3 Stack的代码片段管理工具t3code开发实践 1. t3code 是什么从 T3 Stack 出发的项目定位与选型思考第一次看到 t3code 这个名字很多人会以为它又是个轮子型的代码生成器或者某个在线编译器。实际情况是我在业余时间用它做了一个基于T3 Stack的代码片段管理工具核心逻辑很简单把日常开发中零散的命令、配置片段、正则表达式、Shell 脚本统一收进一个带标签体系的 Web 应用里需要的时候直接用浏览器搜出来复制不用再翻聊天记录和本地笔记。T3 Stack 是近年全栈开发圈里讨论度很高的一套组合拳主推Next.js TypeScript Tailwind CSS tRPC这个组合解决了我最头疼的问题类型安全。传统的全栈开发里前端调接口传参、后端返回数据总有一个环节要靠手写类型定义或者阅读接口文档来对齐稍不注意字段名拼错就是线上 bug。而 tRPC 的思路是让前端直接调用后端函数类型从数据库到 UI 一路贯通改一个字段前端立刻标红。这在 t3code 这种以增删改查为主的工具类项目上收益非常直观。我原本考虑过用 Remix 或者 Nuxt但评估下来T3 Stack 对 TypeScript 的拥抱程度最彻底而且 Next.js 的生态足够成熟Vercel 部署几乎零成本。t3code 项目本身没有复杂的业务规则它是一个典型的 CRUD 应用非常适合拿来体验 tRPC 的完整工作流。如果你也想做一个个人工具型全栈项目T3 Stack 的性价比很高。整个项目的技术选型不是拍脑袋定的我列过一张对比表最终敲定的原因后面会展开讲。方案类型安全程度前后端分离度部署成本适合场景传统 REST API React弱需手写类型高需维护 API 文档中大型项目、多端复用GraphQL Apollo强但配置复杂高需维护 Schema高复杂数据聚合Next.js 全栈 API Routes中接口和类型分离低前后端同仓低简单应用、SSRt3codeT3 Stack极强端到端类型安全低函数直调极低个人工具、中小型全栈应用这个选择的过程本质上是在开发效率和架构复杂度之间做取舍。t3code 不需要开放 API 给第三方不需要多客户端复用前后端同仓就是最好的形态。2. 从零初始化create-t3-app 的配置细节与工程结构初始化 t3code 的过程非常顺滑官方提供了脚手架命令直接在当前目录创建项目。pnpm create t3-applatest t3code脚手架会列出一堆可选项我当时勾选了NextAuth、Prisma、Tailwind CSS、tRPC没有勾 DrizzlePrisma 生态更成熟后面会展开说Tailwind 必选因为它是 T3 视觉风格的一部分。初始化完成后目录结构已经帮你把依赖注入和主流程文件搭好了不用自己从零配置 tsconfig、tailwind.config 和 trpc 客户端。这里有必要解释一下为什么 T3 Stack 默认帮你做这些事却仍然很灵活。它的核心理念是你只需要关注业务代码基础设施已经按最佳实践预置。比如app/api/trpc/[trpc]/route.ts这个文件脚手架直接帮你写好了 Next.js 的 route handler把 tRPC 的请求接入到 Next.js 的 App Router 上。server/auth.ts里帮你把 NextAuth 的配置文件和 tRPC 的上下文串起来用户登录状态会自动注入到每个查询里。这种约定优于配置的做法对个人项目非常友好。第一次启动时的命令也很常规pnpm dev打开http://localhost:3000看到的是 Tailwind 生成的默认首页。此时 t3code 还只是个空壳真正的搭建工作才开始。脚手架生成的目录结构我建议认真理解几个核心文件因为后续所有代码都是在这些文件上扩展的src/server/api/root.tstRPC 的路由聚合入口所有子路由在这里合并src/server/api/routers/实际业务路由目录src/server/db.tsPrisma 客户端实例src/trpc/server.ts服务端调用 tRPC 时的辅助函数src/trpc/react.tsx前端 React 的 Provider 配置做 t3code 这种 CRUD 工具时最值得关注的就是root.ts和routers/目录因为所有业务逻辑都在这里定义。我后续的计划是为代码片段建一个snippetRouter里面写查询和变更逻辑前端通过api.snippet直接调用对应的函数完全不需要写 HTTP 请求代码。3. 数据层的骨架设计Prisma 模型、关系设计与会话绑定t3code 的第一个版本数据模型非常简单用户、代码片段、标签。但即使简单模型设计也得把扩展性考虑进去避免后期重构。我在schema.prisma里先定义了三个核心模型model User { id String id default(cuid()) name String? email String? unique emailVerified DateTime? image String? accounts Account[] sessions Session[] snippets Snippet[] } model Snippet { id String id default(cuid()) title String description String? code String language String tags Tag[] userId String user User relation(fields: [userId], references: [id]) createdAt DateTime default(now()) updatedAt DateTime updatedAt } model Tag { id String id default(cuid()) name String unique snippets Snippet[] }随后定义了 Snippet 和 Tag 之间的多对多关系中间表由 Prisma 自动生成。因为 t3code 是个人工具所以每个片段都绑定到创建者用户通过userId字段关联到 User 表。实际写完后执行迁移pnpm prisma migrate dev --name init这个命令会创建数据库表结构并且自动生成 Prisma Client。选择 Prisma 而不是直接写 SQL 的原因在于 t3code 中的查询逻辑几乎都是从 UI 层触发的Prisma 的类型提示和自动补全能让我少踩很多字段名拼写错误的坑。一个值得注意的细节Tag模型中的name字段我加了unique约束这样同一个标签在数据库里只会有一条记录避免标签重复导致界面混乱。如果你做的是一个面向多用户开放的项目这个约束可能需要改成unique([name, userId])复合唯一让不同用户的标签互不干扰。t3code 是单用户工具所以我保留了全局唯一。用户和片段的关系绑定是 t3code 的一个关键点。因为在 T3 Stack 中tRPC 的 context 里已经注入了会话信息服务端可以直接拿到当前登录用户的 ID然后把这个 ID 写入 Snippet 的userId字段。整个写入过程是类型安全的不用担心传错用户 ID。4. tRPC 路由的编写节奏query 与 mutation 在实际业务中的分工搞定数据模型接下来就是 t3code 最核心的编码环节tRPC 路由。如果你第一次接触 tRPC可以先把它理解为把后端逻辑从 HTTP 接口层提升到了函数调用层。每个router里定义的.query相当于传统的GET请求.mutation相当于POST/PUT/DELETE请求但调用方式变成了api.snippet.getAll()并且返回值会带上 TypeScript 类型推断编辑器里能直接看到字段。t3code 的业务路由分为两类。第一类是无副作用的查询操作例如获取当前用户的片段列表getAll: protectedProcedure .input(z.object({ tag: z.string().optional() }).optional()) .query(async ({ ctx, input }) { return ctx.db.snippet.findMany({ where: { userId: ctx.session.user.id, ...(input?.tag ? { tags: { some: { name: input.tag } } } : {}), }, orderBy: { updatedAt: desc }, include: { tags: true }, }); }),这里的protectedProcedure是脚手架默认提供的一个高阶过程它要求用户必须登录才能调用。如果未登录tRPC 会直接抛异常前端也会收到统一的错误提示。z.object来自 Zod用于给输入参数做运行时校验。这个设计让我不用再写一堆 if/else 去判断参数是否合法Zod 自动完成。代码片段列表通常是个人笔记类应用的请求大头这里没有做复杂的分页直接用orderBy updatedAt倒序排列对个人项目来说远没到性能瓶颈。后续如果片段量大了再考虑 cursor 分页。第二类是 mutation即创建、更新、删除。t3code 的创建片段是整个应用最常用的操作我写了一个create路由create: protectedProcedure .input( z.object({ title: z.string().min(1).max(100), description: z.string().max(500).optional(), code: z.string().min(1), language: z.string().default(plaintext), tags: z.array(z.string()).optional(), }) ) .mutation(async ({ ctx, input }) { const snippet await ctx.db.snippet.create({ data: { title: input.title, description: input.description, code: input.code, language: input.language, userId: ctx.session.user.id, tags: { connectOrCreate: (input.tags ?? []).map((name) ({ where: { name }, create: { name }, })), }, }, include: { tags: true }, }); return snippet; }),这里最值得说的是connectOrCreate它完美契合了标签这种有则连接无则创建的业务场景。比如用户输入了一个新标签 正则如果标签表里没有这个名字Prisma 会先创建这个标签再把它和片段关联起来如果已经有就直接建立关联。这个操作在原生 SQL 里要写好几条语句而 Prisma 用一条命令就搞定了。更新和删除的写法大同小异就不再贴代码了。核心思路是所有带副作用的操作都放在 mutation 里所有纯数据读取都放在 query 里这个分工能让代码结构非常清晰也方便后续加缓存策略。4.1 服务端调用与前端调用的对称性t3code 的前端调用方式和服务端路由定义几乎是对称的。你不需要写任何 fetch 或者 axios 代码直接用api.snippet.getAll这样的 Hook 就行。React Query 帮你处理了状态管理、loading、缓存和失效。这种开发体验是我选择 T3 Stack 的最大理由。前端调用代码很直白const { data, refetch } api.snippet.getAll.useQuery({ tag: activeTag }); const createSnippet api.snippet.create.useMutation({ onSuccess: () { refetch(); }, });useQuery的结果会自动缓存标签切换时如果查询参数变了React Query 会重新拉取useMutation的onSuccess回调里调用refetch确保新片段创建后列表立即更新。整套链路下来前端几乎不用关心数据请求的细节业务状态都交给库去维护。5. 界面层的 Tailwind 实践从设计稿到组件落地的取舍功能写完之后最难啃的是界面。T3 Stack 自带 Tailwind CSS好处是不用写单独的 CSS 文件所有样式都放在 class 字符串里。坏处是如果设计系统不提前定好写到后面 class 会越来越长越来越乱。t3code 的定位是个人效率工具所以我没追求花哨的视觉效果核心目标是一眼看清代码三步内复制片段。5.1 布局设计与响应式页面布局上我用了 Tailwind 的 flex 和 grid 组合。整体分为三栏左侧标签导航、中间片段列表、右侧详情预览。这个布局在桌面端体验最好但手机端就需要重新调整。我用了 Tailwind 的响应式前缀来简化适配div classNameflex h-screen flex-col md:flex-row {/* 标签侧边栏 */} aside classNamehidden w-48 shrink-0 flex-col md:flex / {/* 列表区域 */} main classNameflex-1 overflow-y-auto / {/* 预览区域 */} section classNameflex-1 flex-col p-4 md:border-l / /divhidden md:flex是手机端 Tailwind 布局里最常用的组合之一默认隐藏标签栏在桌面宽度才显示。这个改动比写 JavaScript 判断要优雅得多。5.2 代码高亮与编辑体验代码高亮是片段管理工具的脸面。t3code 最初用的react-syntax-highlighter它在 Next.js 的 App Router 下有个坑highlight 组件体积很大打包时容易触发 Webpack 的性能警告。后来我换成了shiki搭配rehype-pretty-code。使用 shiki 时的基本姿势是在服务端渲染时生成高亮后的 HTML前端直接展示既避免了客户端解析大依赖又能支持很多现代主题。适用 shiki 时在服务端组件里这么写import { codeToHtml } from shiki; const html await codeToHtml(code, { lang: language, theme: github-dark-dimmed, });codeToHtml是同步 API返回的结果是一段完整的 HTML前端用dangerouslySetInnerHTML渲染即可。这里的取舍是虽然牺牲了客户端动态高亮的能力但极大提升了首屏速度而且 t3code 的代码片段基本都是静态内容。5.3 主题色与视觉细节Tailwind 自定义主题色的姿势并不复杂。我在tailwind.config.ts里配置了自己的调色板整体走 dark mode 风格因为代码片段在浅色背景下高亮效果不够炫theme: { extend: { colors: { surface: #1e1e2e, primary: #cdd6f4, accent: #f38ba8, muted: #585b70, }, }, },配色这块没有用标准的前端库而是参照了开源的 Catppuccin 配色方案视觉上比较耐看。Tailwind 最大的优势就是随手可调改色板只需要改配置界面全部实时生效。6. 认证与权限NextAuth 在 t3code 中的集成路径t3code 虽然是个人工具但我不希望任何人打开网址就能看到我的代码片段所以登录验证是必须的。T3 Stack 脚手架默认集成了 NextAuth支持 GitHub 第三方登录和 Credentials 登录。我优先选了 GitHub OAuth原因很简单个人项目的账号体系拿来即用不用维护短信、邮箱、密码重置这一堆东西。6.1 提供者配置在server/auth.ts里配置 GitHub Providerimport GitHub from next-auth/providers/github; providers: [ GitHub({ clientId: process.env.GITHUB_CLIENT_ID, clientSecret: process.env.GITHUB_CLIENT_SECRET, }), ],然后在 GitHub 的 Settings 里创建一个 OAuth App回调地址填http://localhost:3000/api/auth/callback/github生产环境换成自己的域名拿到 Client ID 和 Secret写进.env文件。这个环节有个很容易踩的坑回调地址写错登录时会报 redirect_uri 不匹配。我之前在本地跑通后部署到 Vercel忘了把回调地址从 localhost 改成线上域名卡了整整一小时。建议在 GitHub OAuth App 配置多个回调地址本地和线上分开并逐个验证。6.2 受保护路由与 tRPC 的联动T3 Stack 里NextAuth 的会话和 tRPC 的上下文是打通的。只要用户在 GitHub 登录成功后ctx.session.user就是真实的用户对象。在 tRPC 路由里用protectedProcedure替代publicProcedure就可以直接拦截未登录用户让未登录请求要么被重定向到登录页要么被返回错误。我还做了一层额外的校验由于 t3code 的片段都属于个人用户即使登录用户不是本人也不能访问别人的片段。所以在getAll查询里显式加上userId: ctx.session.user.id过滤。这个做法比依靠路由隐藏更安全也不容易因为前端跳错了路由而泄露数据。7. 部署到生产环境的几个关键卡片Vercel 与数据库托管t3code 的部署我选了 Vercel PlanetScaleMySQL但使用过程中PlanetScale 后来调整了服务策略所以如果你现在要部署我更建议直接考虑Vercel部署 Next.js 应用和 GitHub 仓库直接关联push 后自动构建上线自带 HTTPS 和域名绑定。Supabase基于 Postgres兼容 Prisma免费额度对个人项目足够而且自带 Storage 可以存文件。Neon无服务器 Postgres自动暂停和扩展冷启动略有延迟但个人项目无碍。我在部署时踩过一个和 Prisma 相关的重要坑Vercel 的无服务器环境默认不允许保持数据库连接。如果你的 Prisma 客户端每次都新建连接很快会打满数据库连接数。解决办法是在src/server/db.ts里给 Prisma 客户端加上全局单例缓存。import { PrismaClient } from prisma/client; const globalForPrisma globalThis as unknown as { prisma: PrismaClient | undefined; }; export const db globalForPrisma.prisma ?? new PrismaClient({ log: [query, error], }); if (process.env.NODE_ENV ! production) globalForPrisma.prisma db;这段代码的原理是利用 Node.js 的globalThis对象做缓存生产环境中每个 Serverless 函数实例复用同一个 PrismaClient 实例避免重复创建开发环境则每次都创建新的方便热更新。没有这个缓存你的数据库连接池会莫名其妙地被 Vercel 断开然后在日志里看到一排PrismaClientInitializationError。部署完还要记得设置环境变量。Vercel 的 Project Settings 里把DATABASE_URL数据库连接串和GITHUB_CLIENT_ID、GITHUB_CLIENT_SECRET全部配置好。这个步骤很容易被忽略一旦漏配线上应用会在启动时立刻抛错。8. 踩坑记录我在 t3code 开发中遇到的实际问题工具类的项目开发过程中最大的成本往往不是业务逻辑本身而是那些看起来不复杂但极其消耗时间的环境问题。我完整跑完 t3code 之后整理了三个最典型的坑。8.1 Prisma 和 Next.js 热更新的兼容性问题开发时如果改了schema.prisma并运行prisma migrate在 Next.js dev server 还开着的情况下会发生模型缓存没有完全更新、页面白屏或运行时异常。解决办法是每次跑完 migrate 后手动刷新页面仍然出问题就直接重启 dev server。这属于踩过才知道的坑官方文档提到过但描述不详细开发时容易误以为是代码逻辑 bug。8.2 NextAuth 在 App Router 下的 session 检查t3code 的页面我有两种渲染模式列表页用服务端组件方便首屏直接拿到数据表单页用客户端组件交互更灵活。但在 App Router 下你没法在服务端组件里直接调用useSessionHook只能改用server/auth.ts里导出的getServerSessionimport { getServerSession } from next-auth; import { authOptions } from ~/server/auth; const session await getServerSession(authOptions);如果不在服务端组件里认真判断 session某些页面会闪烁登录后内容很影响体验。T3 Stack 的脚手架虽然预置了getServerSession的封装但最佳实践是服务端组件负责拿 session 做渲染决定客户端组件负责交互不要再在全局布局里混用。8.3 Tailwind 的 class 扫描范围Tailwind 在 t3code 中默认扫描src/**/*.{ts,tsx}如果你把某些样式写在更外层目录比如放在lib/里动态拼接 classTailwind 默认不会生成对应的 CSS界面会突然没有样式。这种 bug 的排查成本极高因为 look like 是样式没生效实际是Tailwind 根本没把你那个 class 编译进产物。把需要静态存在的知名 class 全部放到content配置里能避免这种问题。content: [./src/**/*.{ts,tsx}],另外t3code 的所有片段数据没有做服务端搜索后续如果要做全文检索可以考虑加 Postgres 的全文索引或者直接用 Supabase 的向量检索做语义搜索。那是另一个阶段的事了目前先保持简单。9. 从开发到使用t3code 的日常体验与后续路线t3code 从代码结构设计到所有功能落地我前后用了不到一个周末的时间。核心工作集中在 tRPC 路由、Prisma 模型、前端 React 组件三个部分。真正让开发速度提升的部分是 T3 Stack 把类型安全和数据层基础设施全都铺好了我只用关心业务逻辑本身。相比以前做前端项目时要花大量时间联调接口、排查字段名这种全栈类型安全的体验是一种结构性提速。日常使用的体验是我在浏览器打开 t3code左侧选标签中间扫列表右侧直接复制代码。新增片段时用表单填写标题、粘贴代码、输入标签名提交后列表自动刷新。整个过程不超过十秒。数据库里已经存了上百条常用的正则和 Shell 命令再也没出现过找到一条好命令但忘了存哪的情况。如果接下来继续迭代我会考虑这几个方向给代码片段加星标收藏、支持按语言筛选、做站内全文搜索。搜索是一个比较核心的功能等数据量上来后再补也不迟。目前的 t3code 已经很契合我的个人使用习惯这也是做个人工具最爽的一点不用迁就需求文档自己就是产品经理。最后再分享一个小经验如果你也想做一个类似的个人工具不要纠结于技术栈是不是最新最热。T3 Stack 的好处在于它把所有东西收敛成了一门手艺TypeScript 从后端到前端全程护航Prisma 管数据Tailwind 管样式tRPC 管接口。你唯一要做的就是把业务逻辑写好别的交给框架。这种带着镣铐跳舞的开发体验反而比一上来就自己拼一套前后端分离的脚手架要高效得多。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询