☰
t3code全栈实战:代码生成器把样板开发压缩到五分钟
2026/10/27 23:02:14 网站建设 项目流程

如果你和我一样,经常要从零开始撸一个全栈项目,大概率经历过这么几个场景:初始化脚手架、连接数据库、手写CRUD、定义类型和校验、再折腾半天登录态。这些事不难,但架不住每个项目都要重复一遍。t3code就是我在这个场景里挖到的一个很顺手的工具,它不是框架,也不是ORM,而是一套围绕TypeScript全栈开发的代码生成器。用顺手之后,原来小半天的初始化工作,现在基本五分钟搞定,今天就把我实际使用t3code的完整流程和经验拆给你。

1. 先搞清楚 t3code 是干什么的,再决定要不要上车

1.1 它瞄准的是全栈样板代码这块硬骨头

t3code这个名字,熟悉“T3 Stack”的人一眼就能联系起来。T3 Stack是当下前端圈很流行的一套组合拳:Next.js做框架、TypeScript做类型、Tailwind写样式、tRPC做API通信,再配上Prisma操作数据库。这套组合的好处是类型安全从头贯穿到尾,坏处是样板代码特别多。每开一个新项目,你都得把那些“长得几乎一样”的代码重新写一遍:页面组件、表单校验、接口路由、数据库表定义,翻来覆去就那些东西。

t3code干的事,就是把这些重复劳动自动化。它通过一个命令行工具,在你初始化好的T3项目上继续“生成”代码。比如你告诉它“帮我生成一个User模型”,它就会自动产出Prisma的模型定义、tRPC的CRUD路由、前端的列表页和表单页,甚至连zod校验规则都帮你写好了。核心价值不是代码多神奇,而是把“绝大多数全栈项目都要做的那80%基础功能”从手写变成了命令执行。

1.2 为什么我最终选它,而不是继续手写

说实话,市面上脚手架工具并不少,create-t3-app能帮你初始化项目,但之后写CRUD依然靠人工。有些低代码平台能拖拽生成,但锁死太严重,后期改个逻辑都得绕远路。t3code给我最直观的感觉,是“生成的是代码本身,而不是一个黑盒”。它产出的文件干干净净落在你的工程目录里,你可以随便改、随便重构,没有任何运行时依赖。这就好比请了个资深助理,帮你把初稿写好了,但最终改不改、怎么改,仍然是你自己拿主意。

另一个原因是它跟T3 Stack的配合度足够高。t3code对Next.js的App Router、tRPC的router结构、Prisma的schema格式都有内置约定,生成的代码直接就能跑,几乎不用手动调整。这种“约定优先”的设计,让团队协作时的代码风格也统一了不少,新人接手项目时,看到的路由、校验、数据访问代码都是同一个套路。

1.3 适合谁来用,以及什么时候别用它

如果你是以下类型,t3code大概率能帮你省下很多时间:

  • 经常给客户做中小型全栈项目的开发者;
  • 团队需要快速搭建后台管理系统的场景;
  • 刚学完T3 Stack,想快速上手跑通“从数据库到页面”全链路的初学者;
  • 喜欢DRY原则(Don't Repeat Yourself),对重复样板代码深恶痛绝的人。

反过来,如果你的项目极度定制,比如复杂的权限矩阵、非标准的数据关联、或者需要跟现有的老代码库深度整合,那t3code生成的东西更多是“参考”,你不能无脑依赖。它更适合项目初期的骨架搭建和常规CRUD,而不是替你处理所有业务复杂度。

2. 环境准备与初始化:5分钟跑通一个t3code项目

2.1 需要准备的环境和依赖

t3code目前是一个Node.js命令行工具,所以环境要求很简单:

  • Node.js 18及以上(推荐20 LTS);
  • 包管理器用npm、pnpm或yarn,我个人更推荐pnpm,安装速度和安全度都更好;
  • 一个干净的目录,别放在已有的复杂项目里测试。

如果你有Docker,后面跑数据库会更方便,但这不是必须。单靠本地的SQLite也能跑通全流程。

2.2 初始化一个全新的T3项目

t3code本身不会替代create-t3-app,而是建立在它之上。所以第一步还是创建基础项目:

pnpm create t3-app@latest my-app

按照引导选择需要的功能。我的建议是:Next.js用App Router、TypeScript当然要开、Tailwind看项目需要、tRPC必选、Prisma必选、NextAuth可以先不选,等需要登录时再集成。初始化完成后,进入项目目录:

cd my-app

接下来安装t3code CLI:

pnpm add -D t3code

这里有个细节:t3code是作为开发依赖安装的,因为它只是一个代码生成工具,不会参与生产构建,这一点很合理。

2.3 第一次运行 t3code init

装好之后,运行:

pnpm t3code init

它会读取当前项目的结构,在根目录生成一个t3code.config.ts配置文件。这个文件是t3code的灵魂,里面定义了生成的默认模板路径、目标目录、以及一些全局约定。生成的配置文件大概长这样:

import { defineConfig } from 't3code' export default defineConfig({ // 模型定义存放的位置 schemaDir: './prisma/schema.prisma', // 生成的服务端路由输出目录 serverDir: './src/server/api/routers', // 生成的前端页面输出目录 clientDir: './src/app', // 默认是否生成表单校验文件 withZod: true, // 生成代码时是否覆盖已存在的文件 overwrite: false, })

你不需要立刻改它,但最好知道这些配置项的位置。后续我为了项目规范,把withZod保持为true,这样生成的表单自动带校验,省很多事。

2.4 跑一个最简单的生成命令试试水

配置文件就绪后,可以先拿最简单的模型练手。比如生成一个 “Tag” 模型:

pnpm t3code generate model "Tag { id String @id @default(cuid()) name String }"

这条命令的意思是:让t3code创建一个名为Tag的模型,字段包含id和name。命令跑完后,去看prisma/schema.prisma,你会发现末尾多了一段:

model Tag { id String @id @default(cuid()) name String }

然后去src/server/api/routers目录,多了tag.ts路由,里面包含了getAll、getById、create、update、delete五个tRPC procedure。再看前端,src/app/tags/page.tsx已经是一个完整的列表页面,甚至带了一个新增弹窗和编辑功能。第一次看到这个效果时,我确实被爽到了。

注意,t3code并不会自动帮你执行数据库迁移,需要手动跑:

pnpm prisma migrate dev --name init_tag

然后把tRPC路由挂载到主router上,如果你是第一次生成,需要手动编辑一下src/server/api/root.ts,把tagRouter加进去。这一步之后的版本可能自动处理,但我目前用的版本还是需要手动接一下,不算麻烦。

3. 核心实战:用 t3code 生成一套完整的、可直接上线的文章管理模块

3.1 提前把模型设计好,而不是边写边想

代码生成器的最大优势是快,但如果你模型设计不清晰,生成的代码改起来也费劲。我建议先用自然语言把模型关系理清楚,再交给t3code。

以“文章管理”为例,需要两个模型:Article(文章)和Category(分类),文章属于一个分类,分类下有多个文章。用t3code的DSL(领域专属语言)来定义:

pnpm t3code generate model "Category { id String @id @default(cuid()) name String unique articles Article[] }" pnpm t3code generate model "Article { id String @id @default(cuid()) title String content String published Boolean @default(false) categoryId String category Category @relation(fields: [categoryId], references: [id]) }"

这里要注意关系字段的写法。Prisma的关系定义比较严格,如果你直接写articles Article[],t3code能解析出另一端,但建议在Article这边把外键和关系绑定都写清楚,不然生成出来的代码在查询时可能缺少include的关系参数。

3.2 看看 t3code 到底生成了哪些文件

执行完上面两条命令后,整个项目发生的变化,我列个清单:

文件路径作用
prisma/schema.prisma新增 Category 和 Article 两个模型
src/server/api/routers/category.tsCategory 的完整 CRUD 接口
src/server/api/routers/article.tsArticle 的完整 CRUD 接口
src/app/categories/page.tsx分类列表页
src/app/articles/page.tsx文章列表页
src/app/articles/new/page.tsx新增文章表单页
src/app/articles/[id]/edit/page.tsx编辑文章详情页
src/lib/validations/article.tszod 的校验规则定义

特别提一下article.ts路由的生成内容。t3code生成的代码不是简单糊弄,它会根据字段类型自动选择合理的查询参数。比如published是个布尔字段,生成的查询接口里会多一个onlyPublished的可选筛选参数;categoryId存在,生成接口里会默认把category关联数据用include带出来。这些细节如果手写,常常要花不少时间调,但现在你只需要检查一遍,基本能直接用。

3.3 手动补一步:把路由挂到主 router 上

不知道为什么,t3code目前不会自动修改root.ts。这是很正常的,因为自动扫描文件并改写代码容易出错,它刻意把主动权留给你。打开src/server/api/root.ts,内容现在大概是:

import { createTRPCRouter } from "~/server/api/trpc"; import { articleRouter } from "~/server/api/routers/article"; import { categoryRouter } from "~/server/api/routers/category"; export const appRouter = createTRPCRouter({ article: articleRouter, category: categoryRouter, });

这个文件可能已经帮你引好了article和category,如果你的版本没有,那就手动加上。这段代码本身不难,你要做的事就是把router实例挂载到appRouter对象下。挂载完,跑到http://localhost:3000/api/trpc就能看到你的接口文档(tRPC默认开启playground)。

3.4 生成前端页面后的自定义需求

生成的列表页通常是一个基础表格,够用但不算美观。我会做三处自定义:

  1. 把“发布日期”显示成格式化后的日期;
  2. 文章列表页增加一个“按分类筛选”的下拉框;
  3. 编辑页的内容字段从textarea改成Markdown编辑器。

这些改动都是在生成的代码上继续修改,t3code生成的代码可读性确实不错,没有奇怪的抽象层,直接上手改就是。这一点我很喜欢,因为很多代码生成器生成的代码像天书,根本不敢碰,而t3code生成的代码就跟自己写的差不多。

改完之后请记得跑一遍类型检查:

pnpm tsc --noEmit

如果报错,基本都集中在关联字段上。比如文章列表页里,如果你访问了article.category.name,但tRPC的返回类型里没有包含category,那就得去routers/article.ts的getAll里检查include写法。t3code生成的代码通常会包含,但如果你改了查询条件,可能就丢了。

4. 避坑指南:我在 t3code 上踩过的 6 个坑

4.1 生成器版本和项目依赖版本不匹配

我第一次用的时候,t3code还是0.9.x版本,项目里用的是Next.js 14。后来我把项目升级到Next.js 15,又更新了tRPC到11,结果t3code生成的代码用的是旧版tRPC的写法,导致接口报错。所以,升级项目大版本之后,很有必要也升级t3code,并跑一下生成器自带的兼容性检查。一般在t3code init时它会检测当前项目的依赖版本,如果版本过新,可能会提示你升级CLI。

4.2 默认不覆盖已存在文件,但你总会想覆盖

配置文件里overwrite: false是一个保护机制。如果你对page.tsx做了大量自定义,下一次运行t3code generate时,它不会覆盖你的文件,而是生成一个新的文件到.t3code/backups下面。这个机制能防止误操作,但也容易让人困惑。我的做法是:模型刚建好,还没开始手改时,用默认模式;一旦我改过页面,后续就不会再针对这个模型跑 generate model,而是手动写代码,或者只覆盖单独的router文件。如果你确定要覆盖,可以加上--force参数:

pnpm t3code generate model "Article { ... }" --force

但用了就要对结果负责,建议先git diff看看改动内容。

4.3 关系命名和 Prisma 的默认命名不一致

给模型定义关系字段时,t3code基本是照抄你的字符串描述。如果你写:

pnpm t3code generate model "User { posts Post[] }"

它会在另一端自动生成author字段吗?不会,它只会生成一个posts数组,但Post那边的userId字段需要你自己加上。如果漏了,Prisma migrate时会报错。我踩过的坑是在生成评论模型时,忘了在Comment里写authorId,结果整链路的查询都跑不通。建议所有多对多或一对多关系,在两端都明确写清字段。

4.4 枚举类型生成后无法直接用字符串联合

T3 Stack风格里,后端枚举通常用Prisma的enum,但前端组件里有时候只需要字符串联合类型,两者不是自动联通的。t3code对Prisma enum的处理是生成对应的zod枚举引用,但前端页面里下拉框的选项值是写死的字符串数组。如果你修改了Prisma的enum值,前端不会同步。我的习惯是把这类枚举定义放在一个共享的constants.ts文件里,然后前后端都引用这个文件,避免手改两处。

4.5 批量生成多个模型时,router 自动导入会乱

一次跑多行generate model命令时,t3code会逐个处理。如果两个模型之间有依赖关系,最好的做法是先定义被依赖的模型(如Category),再定义依赖方(Article)。同时生成完记得检查root.ts,因为多次生成的导入语句可能重复,或者缺少某个路由。我习惯于在生成完所有模型后,一次性整理root.ts,而不是每个模型建完后去改。

4.6 自定义模板时变量名千万别乱用

t3code支持自定义模板,你可以在项目里建.t3code/templates/目录,放入.ejs或.hbs模板文件。这里有个隐蔽的坑:模板里如果用了title这个变量,它会自动替换成模型描述里的title字段值,但如果你模板内部声明了同名变量,会导致渲染结果错乱。我建议统一用模型定义时的字段名,模板里不要自作主张去创建类似title、name这种容易撞车的变量。实在要用,加前缀,比如modelTitle。

5. 三个提升效率的进阶技巧

5.1 写一个自定义模板,统一团队的数据表格风格

默认生成的列表页是极简的Tailwind表格,样式谈不上丑,但离“可以直接交差”还有距离。我们团队自己维护了一套.t3code/templates/list-page.tsx.ejs,生成出来的列表页自动带分页、搜索栏、批量删除按钮,并且右上角是固定的“新建”按钮。模板内用ejs的循环语法:

<DataTable columns={[ <% fields.forEach(function(field) { %> { key: '<%= field.name %>', label: '<%= field.label %>' }, <% }); %> ]} />

这样生成出来的页面一出来就能接入公司内部的DataTable组件,节省了至少每人半天的时间。具体语法可以看t3code文档,但思路就是这样:把团队的规范沉淀成模板。

5.2 用 watch 模式实现“改模型即刷新代码”

我自己开发时有个习惯:先用中文把模型描述写出来,然后运行一条带watch的命令:

pnpm t3code watch

这个命令会监听prisma/schema.prisma的变化,一旦你手动修改了Prisma模型定义,它就会自动重新生成对应的tRPC路由和页面。这个功能非常适合原型阶段,改字段比改代码快多了。不过注意,它同样不提供自动覆盖,如果你改了页面,watch模式可能会持续生成备份文件,烦得很。所以我只在最早期的建模阶段用,一旦开始定制前端,就把它关掉。

5.3 配合 Git hooks,让生成的代码自动过一遍格式化

t3code生成的代码结构是完整的,但缩进和换行风格可能跟你项目里的Prettier配置不一致。我在package.json里加了这个脚本:

{ "scripts": { "gen": "t3code generate && prettier --write src prisma" } }

每次跑完生成,顺手格式化,避免提交代码时出现大量diff噪音。如果你们团队用lint-staged,也可以在生成完成后自动执行。这个习惯很小,但能让code review更轻松。

最后再分享一个我自己的习惯

现在开新项目,我已经形成了一条固定流水线:create-t3-app初始化,t3code init装好配置,然后花十分钟把核心数据模型用自然语言描述清楚,再一次性交给t3code批量生成。生成的代码我从来不会直接信,但也不会去重写。我会花十五分钟从头到尾翻开每个文件,看着它生成的代码想想“如果是我写,这里会不会不一样”。大部分时候,它生成的和我手写的差异很小,只有极少数业务需要额外封装。这个过程中养成的习惯是:永远不要为了“省事”而跳过检查生成的代码。代码生成器是帮你把重复劳动压缩掉,不是让你变成甩手掌柜。理解了这一点,t3code就不再只是一个工具,而是你在全栈开发中的得力副驾。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询