news 2026/10/27 16:29:12

T3 Code全栈开发实战:从TypeScript到数据库的端到端类型安全链路

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
T3 Code全栈开发实战:从TypeScript到数据库的端到端类型安全链路

1. 从 T3 Code 说起:这套全栈方案到底解决了什么

先聊一个现象:现在做全栈项目,最大的痛点往往不是功能本身,而是前后端交界处那一堆手工维护的 TypeScript 类型。你改了后端接口的某个字段,前端对应的类型定义没同步改,等真跑到页面才发现数据对不上,轻则页面报错,重则线上事故。我刚接触t3code时真正被吸引的一点,就是它把"类型安全"这条线从前端贯穿到了后端,数据库里长什么样,API 返回什么结构,组件拿到什么数据,整条链路完全一致。

t3code这个词在社区里通常指代以 T3 Stack(T3 技术栈)为核心搭建的全栈代码工程。T3 这个名字不是随便起的,它由几个关键词的首个字母组成:TypeScript、Tailwind CSS、tRPC,再加上它依赖的 Next.js 与 Prisma 等现代工具。如果你做过一段时间全栈开发,会发现这套组合并不是把流行框架强行堆在一起,而是针对"一个人或小团队做完整应用"这个真实场景做的精选。它解决的核心问题有三类:

  • 端到端类型安全:定义一次,前端、后端、数据库三层共用一个类型模型,改一处,关联的地方全部提示。
  • 工程化起步成本:create-t3-app 一条命令拉出可运行的项目,路由、鉴权、ORM、样式全部配好,省去繁琐的 boilerplate。
  • 开发体验的一致性:服务端和客户端共享同一套 TypeScript 语言,不再需要在"写接口文档"和"维护接口类型"上反复横跳。

这篇文章适合两类人:一是对 Next.js 或 React 有一定基础、想上手全栈开发的新手;二是已经写过不少前后端分离项目、被类型不一致和 API 维护折磨过的老手。我会把方案选型的理由、核心路由与数据链路的设计、一次完整的小型应用实操过程,以及我实际踩过的坑和排查方法,都完整写出来。这套东西不玄乎,但它确实能改变你写全栈代码的方式。

2. 方案选型的底层逻辑:为什么偏偏是这几个工具

2.1 从命名看技术基因:TypeScript、Tailwind 与 tRPC 的配合逻辑

T3 Stack 里的三个核心字母已经揭示了它最在意的三件事。TypeScript 提供了基础的类型系统,但光有 TypeScript 还不够,真正麻烦的是前后端之间的"类型断层"。tRPC 就是为了补上这一断层而生的库:它让你在写服务端函数时,这些函数能够像本地函数一样被客户端直接调用,同时自动推导参数和返回值的类型。

我见过不少团队用 REST 风格写接口,每写一个新接口就要在前后端分别定义 DTO、补文档、确认字段类型。时间一长,代码里会出现大量"看似相同、实则松散"的类型副本,改起来极其痛苦。tRPC 的做法是把"接口"抽象成"过程(procedure)",输入端使用 zod 做运行时校验,输出端直接由 TypeScript 推导,前后端共享同一个类型上下文。你不再需要手动维护一份 API 类型声明,服务器端的函数签名本身就是客户端的接口契约。

Tailwind CSS 在这套方案里的角色是"消除样式层面的心智负担"。它不参与类型系统,但它的实用类(utility class)写法让组件开发不再需要反复切换 CSS 文件,设计约束也可以直接用间距、颜色、断点体系表达。对于全栈应用来说,Tailwind 最讨喜的一点是配合 shadcn/ui 等组件体系,可以快速搭出界面,而不会被厚重的 UI 框架绑定。

2.2 为什么选 Next.js 做承载层,而不是 Vite 或纯 Express

很多人会有疑问:tRPC 不是必须搭配 Next.js 才能用,为什么t3code默认就用 Next.js?因为 Next.js 同时承担了"前端页面渲染"和"后端 API 路由"两个角色,而这两者恰好是 tRPC 需要的两个端。Next.js 的 App Router 和 Route Handlers 可以很自然地挂载 tRPC 的 HTTP 服务;同时它的 React Server Components 支持也让页面能直接使用服务端数据,减少了来回请求的负担。

如果用纯 Express 做后端 + Vite 做前端,那么 tRPC 依然可以工作,但你得自己维护两套运行环境、两套构建配置、两套部署流程。T3 方案把运行时统一到一个 Next.js 进程里,开发环境和生产环境都只有一份配置。尤其在小团队或独立开发场景下,这种"单体重于微服务"的选择能大幅减少运维成本。Next.js 的增量静态再生成(ISR)、Server Actions 等功能也能按需引入,灵活性保留得很好。

另外,Next.js 生态里成熟的鉴权方案 next-auth 能与 tRPC 中间件结合,实现"未登录用户禁止调用特定 procedure"。这一步在传统后端框架里需要写很多中间件代码,但在这里只需要在 router 构建时挂一个 protect 方法,类型和权限逻辑会被集中管理。

2.3 数据层的选择:Prisma 与类型系统的自然衔接

T3 Stack 默认推荐 Prisma 作为 ORM,原因是它能从数据库 schema 直接生成 TypeScript 类型。写过 SQL 建表语句的人都知道,数据库字段一变,业务代码里的类型就要手动跟着改,轻度项目还能忍,大型项目非常容易漏改。Prisma 通过prisma generate在每次 schema 变更后重新生成客户端,你的查询结果、写入入参、关联关系全部有类型保障。

这一设计把类型安全的链条延展到了数据库层:Prisma 查出来的模型类型可以直接作为 tRPC 的输出类型返回,前端拿到的数据结构就是数据库结构的投影。在t3code的典型工程里,你会发现server/api/routers下的代码几乎不做 DTO 转换,因为类型已经足够可靠了。

当然,任何一个工具都有适合的场景。Prisma 不适合那种特别复杂的原生 SQL 查询、极度依赖存储过程或数据库高级特性的项目;它更适合大多数 CRUD 为主、关系模型清晰的业务系统。t3code在这一点上的态度很明确:拿了模板先跑通主流程,碰到确实需要手写 SQL 的场景,再通过 Prisma 的$queryRaw逃生舱门绕过即可。

3. 实操准备:创建项目与工程结构解读

3.1 一条命令拉出完整工程:create-t3-app 实战

环境要求其实不复杂:Node.js 18 及以上、npm/yarn/pnpm 任一包管理器、一个能访问包管理 registry 的终端环境。我通常用 pnpm,因为它磁盘占用小、安装速度快,而且对 monorepo 的天然支持在后端有新服务加入时也好用。执行初始化命令时,可以指定项目名:

pnpm create t3-app@latest my-app

安装过程中 CLI 会询问你要启用哪些模块。我默认勾选的项是:Next.js、Tailwind、tRPC、Prisma、NextAuth。如果你暂时用不到鉴权或数据库,可以先去掉 NextAuth 和 Prisma,但保留 tRPC 和 Tailwind,这样初始项目更轻。CLI 还会问你要不要用 ESLint、Prettier,这两个我建议全部开启,因为项目生成后我们会大量依赖类型检查和自动格式化,提前配置好能省掉不少整理代码的时间。

初始化完成后的目录结构大致如下:

├── prisma │ └── schema.prisma ├── src │ ├── app │ │ ├── api/trpc/[trpc]/route.ts │ │ ├── layout.tsx │ │ └── page.tsx │ ├── components │ ├── server │ │ ├── api/trpc/router.ts │ │ ├── api/trpc/trpc.ts │ │ └── db.ts │ ├── styles │ └── trpc │ ├── react.tsx │ ├── server.ts │ └── shared.ts

第一眼看上去文件夹不多,但每一条链路都是有讲究的:app/api/trpc/[trpc]/route.ts是 Next.js 暴露给外界的 HTTP 入口;server/api/trpc/trpc.ts负责创建 tRPC 实例上下文和基础过程;server/api/trpc/router.ts把各个业务 router 合并成一个 appRouter;src/trpc下则是客户端调用时需要用到的封装。这种分层把"类型来源""服务端逻辑""客户端调用"三件事拆得很清晰,新手照着目录走一圈基本就理解了。

3.2 环境变量与数据库初始化:最容易被忽略但最关键的一步

项目生成完,第一件要做的事不是写业务代码,而是把环境变量配好。模板根目录下有个.env.example,我习惯把它复制为.env再逐一填写。核心变量是数据库连接串,Prisma 依赖它跑迁移和查询。比如 PostgreSQL 的连接串一般长这样:

DATABASE_URL="postgresql://postgres:password@localhost:5432/t3code?schema=public" NEXTAUTH_SECRET="your-secret-token" NEXTAUTH_URL="http://localhost:3000"

NEXTAUTH_SECRET是 next-auth 用来加密会话的密钥,生产环境务必用足够长的随机字符串替换掉模板里的默认值。自己在终端生成的办法很直接:

openssl rand -base64 32

连好数据库后,先跑一次初始化迁移:

npx prisma migrate dev --name init

这条命令会读取prisma/schema.prisma,在数据库里创建对应表,并生成本地迁移记录。如果没有这一步,后续启动应用时只要涉及数据库的查询就会直接报错。很多新手卡在"页面能开但登录就崩"的阶段,基本都是这里漏了。

3.3 NextAuth 与 Prisma 的适配:会话类型如何打通

t3code模板里的 next-auth 配置通常放在src/server/auth.ts。Prisma 作为用户存储时,需要先定义好Account、Session、User、VerificationToken这几张标准表。模板默认通过@auth/prisma-adapter来完成适配,配置方式并不复杂:

import { PrismaAdapter } from "@auth/prisma-adapter"; import NextAuth from "next-auth"; import { db } from "@/server/db"; export const { handlers, auth, signIn, signOut } = NextAuth({ adapter: PrismaAdapter(db), providers: [], session: { strategy: "database" }, });

使用数据库会话还是 JWT 会话,取决于你的场景。模板默认是 database 策略,每次请求都会查数据库验证 session;对独立开发的小应用来说,这个问题不大。如果后续流量增长,再切到 JWT 策略也不迟。最关键的一点是类型:为了让 tRPC 上下文里能拿到session.user的类型,你需要手动给 next-auth 的声明文件补充类型。模板里自带的src/types/next-auth.d.ts会做这件事,它的本质是把User的 id、role 等字段扩展进会话对象,这样后续在protectedProcedure中访问ctx.session.user.id就不会是未知类型。

4. 核心链路实操:从数据模型到面向用户的完整功能

4.1 数据建模:用 Prisma Schema 明确业务边界

为了让整条链路可感知,我用一个典型的"链接收藏夹"应用来走通全过程。用户把自己的书籍、文章链接保存下来,可以打标签、标记已读。数据库表的结构设计如下:

model User { id String @id @default(cuid()) name String? email String? @unique emailVerified DateTime? image String? accounts Account[] sessions Session[] bookmarks Bookmark[] } model Bookmark { id String @id @default(cuid()) title String url String tags String[] isRead Boolean @default(false) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt userId String user User @relation(fields: [userId], references: [id], onDelete: Cascade) }

这里两个细节值得说。第一,url 不设唯一索引,因为同一个链接不同用户都可以收藏,真正需要唯一性的是(用户, url)组合,如果业务上有需求,可以再加上@@unique([userId, url])。第二,tags 用 String[] 类型在 PostgreSQL 里会自动变成文本数组,适合标签数量可变、但不需要复杂关联的场景。如果想做标签强关联查询,再单独建 Tag 模型也不迟,但收藏夹这种场景上用简单数组已经够用了。

写好 schema 后再次跑迁移:

npx prisma migrate dev --name add-bookmark npx prisma generate

generate这一步很多人会漏。它负责从最新 schema 生成 Prisma Client 类型,如果没跑,代码里访问prisma.bookmark时会提示对象不存在。

4.2 tRPC Router 设计:input、procedure 与 protectedProcedure

接下来是 tRPC 的 router。在src/server/api/routers/bookmark.ts里定义收藏相关的操作:

import { z } from "zod"; import { createTRPCRouter, protectedProcedure, publicProcedure } from "@/server/api/trpc"; export const bookmarkRouter = createTRPCRouter({ getAll: protectedProcedure.query(async ({ ctx }) => { return ctx.db.bookmark.findMany({ where: { userId: ctx.session.user.id }, orderBy: { createdAt: "desc" }, }); }), create: protectedProcedure .input( z.object({ title: z.string().min(1), url: z.string().url(), tags: z.array(z.string()).default([]), }), ) .mutation(async ({ ctx, input }) => { return ctx.db.bookmark.create({ data: { title: input.title, url: input.url, tags: input.tags, userId: ctx.session.user.id, }, }); }), toggleRead: protectedProcedure .input(z.object({ id: z.string() })) .mutation(async ({ ctx, input }) => { const bookmark = await ctx.db.bookmark.findUnique({ where: { id: input.id }, }); if (!bookmark || bookmark.userId !== ctx.session.user.id) { throw new Error("Bookmark not found or unauthorized"); } return ctx.db.bookmark.update({ where: { id: input.id }, data: { isRead: !bookmark.isRead }, }); }), });

protectedProcedure是模板里预置的基础过程,它的定义通常长这样:在调用实际处理函数之前,先检查ctx.session是否存在,不存在就抛异常。这样做的好处是,每个需要登录的接口都共享同一份鉴权逻辑,而且错误信息统一。input 使用 zod 做校验,也是在 tRPC 启动时的标准姿势:zod 的 schema 既是运行时校验器,也是 TypeScript 类型推导源。客户端传错字段类型、漏传必填字段,会在请求真正进入处理函数之前就被拦截。

4.3 把 Router 挂进根配置:一个容易出错但检查点清晰的步骤

写完子 router 后,需要把它合并到src/server/api/root.ts的appRouter里。这个文件是客户端连接服务端的桥梁,凡是新写的 router 都要在这里登记,否则客户端调用时找不到对应方法。

import { bookmarkRouter } from "@/server/api/routers/bookmark"; import { createTRPCRouter } from "@/server/api/trpc"; export const appRouter = createTRPCRouter({ bookmark: bookmarkRouter, // 其他 router 继续挂在这 }); export type AppRouter = typeof appRouter;

AppRouter这个类型是关键中的关键。后面客户端createTRPCClient或trpc/react里创建 hook 时,都要引用它作为类型参数。类型一旦在这里断掉,前端各种useQuery的返回类型就会全部变成 any,类型安全链路瞬间失效。所以我在项目中习惯将root.ts视为一个"类型集线器"来谨慎维护。

4.4 前端调用:useQuery 与 useMutation 的实际写法

客户端调用在t3code里走的是src/trpc/react.tsx生成的封装 hook。页面组件使用起来几乎是同步调用的体验:

"use client"; import { api } from "@/trpc/react"; import { useRouter } from "next/navigation"; export function BookmarkList() { const utils = api.useUtils(); const router = useRouter(); const { data: bookmarks, isLoading } = api.bookmark.getAll.useQuery(); const createBookmark = api.bookmark.create.useMutation({ onSuccess: async () => { await utils.bookmark.getAll.invalidate(); }, }); const toggleRead = api.bookmark.toggleRead.useMutation({ onSuccess: async () => { await utils.bookmark.getAll.invalidate(); }, }); if (isLoading) return <div>加载中...</div>; return ( <ul> {bookmarks?.map((bookmark) => ( <li key={bookmark.id}> <a href={bookmark.url} target="_blank" rel="noreferrer"> {bookmark.title} </a> <button onClick={() => toggleRead.mutate({ id: bookmark.id })}> {bookmark.isRead ? "标记未读" : "标记已读"} </button> </li> ))} </ul> ); }

不用写 fetch、不用处理 JSON 序列化、不用手动声明响应类型,数据拿到手就已经是带完整类型的Bookmark[]。这种体验与传统 REST 开发方式对比,差异非常大。常见的传统做法是前端定义 interface、后端再定义另一份 model,两层经常对不上;这里只存在一份类型源,那就是 schema.prisma 联合 tRPC 的输入输出推导。

还有一个实用性很强的点:useUtils().xxx.invalidate()可以在某个 mutation 成功后让指定查询重新拉取。这在收藏列表这类场景中非常顺手,不需要自己维护一个全局状态管理器或者手工更新缓存列表。模板里的 React Query 配置已经把这部分封装好了。

4.5 登录态与页面隔离:中间件的实际应用

如果应用需要"未登录用户也能浏览部分页面"或"特定路由仅登录用户可见",可以在 Next.js 中间件层面做第一层控制。模板生成的src/middleware.ts使用getToken检查 session,并维护一个protectedRoutes列表:

import { getToken } from "next-auth/jwt"; import { NextResponse } from "next/server"; const protectedRoutes = ["/dashboard", "/bookmarks"]; export default async function middleware(req) { const token = await getToken({ req }); const isProtected = protectedRoutes.some((route) => req.nextUrl.pathname.startsWith(route), ); if (isProtected && !token) { return NextResponse.redirect(new URL("/login", req.url)); } return NextResponse.next(); }

这里的思路是:中间件只负责"页面能不能进",tRPC 的 protectedProcedure 负责"数据能不能拿"。两者是互补的关系,不能互相替代。只做中间件拦截,用户仍可能通过直接调用 API 端点绕过页面限制;只做 tRPC 校验,未登录用户还是会先加载空壳页面再收到 401 错误。合在一起才是完整的权限控制。

5. 常见问题与排查技巧实录

5.1 tRPC 类型报错:最频繁也最好解决的一类问题

这类错误的表现形式五花八门,但根因往往只有几种。最常见的是路由路径拼错:api.bookmark.getAll被写成了api.bookmark.getALl,TypeScript 会立刻标红。第二种是子 router 没有在root.ts里挂载,检查时把appRouter的 type 展开,会发现缺少对应的命名空间,此时补挂即可。第三种是 input 类型与 zod schema 不一致,比如客户端传入了 number 类型的 id,而服务端定义为 z.string(),请求发出前 tRPC 的类型检查就会提示不匹配。只要遵循"先跑pnpm tsc --noEmit,再看终端报错,再确认 router 挂载和 zod schema"这个顺序,大多数类型问题五分钟内就能定位。

我给团队定的规则是:不要把 tRPC 类型报错当成"编译器找茬",它是服务端契约在生效。如果字段类型改了,不要用as硬转换绕过类型检查,正确做法是回去修改 zod schema 或 Prisma model,让源头更新。

5.2 数据库连接失败:不是代码问题,是环境问题

很多次应用能构建成功但一查数据库就崩,第一反应是 Prisma Client 写错了,实际检查后才发现是环境变量没生效。Next.js 在.env中读取变量时,只会加载项目根目录下的文件,如果用的是 monorepo,配置位置还要根据root的 env 文件路径另行调整。启动应用前,我会先跑一段最基础的查询验证连通性:

const count = await db.bookmark.count(); console.log(count);

如果这个脚本报错,优先确认DATABASE_URL指向的数据库实例是否运行、连接串端口是否正确、数据库账号是否有足够权限。Prisma 的错误信息里通常能提示是连接拒绝、认证失败还是数据库不存在,逐项排查比翻业务代码高效得多。

pnpm prisma migrate dev报错也别急着删库重来。先看迁移文件有没有冲突,如果本地数据库已经被建过表而迁移记录缺失,最简单的办法是重置开发库,明确这是一次破坏性操作,会清空全部数据:

npx prisma migrate reset

5.3 Next.js 的 "use client" 边界问题:触发频率极高的坑

tRPC 的客户端 hook 依赖 React Query,而 React Query 在服务端组件里没有完整运行时支持,所以调用useQuery、useMutation的组件必须标记"use client"。服务平台组件和小型独立组件时,很容易忘记这个指令,结果页面一刷新就报This hook can only be used inside a Client Component。

解决思路不是把所有页面都改成客户端渲染,而是把"客户端交互组件"从服务端页面中拆分出来。比如BookmarkList负责数据交互和按钮点击,它标记为"use client";父级Page保持服务端组件,只负责布局和静态内容。这样既保留 SSR 的优势,又满足 tRPC + React Query 的运行条件。

还有一种情况与缓存有关:在服务端组件里用fetch或 tRPC 服务端调用直接查数据时,Next.js 会默认缓存静态渲染结果,你在页面上刷新看不到新数据。排查这类问题时要看一眼页面是静态生成、动态渲染还是客户端渲染。收藏夹这类强交互页面,我会显式声明动态渲染:

export const dynamic = "force-dynamic";

或者干脆在客户端 hook 里读取数据,用 mutation 成功后 invalidate 的方式来保证数据新鲜度。

5.4 Tailwind 样式不生效:配置覆盖与 class 生成遗漏

t3code工程里 Tailwind 默认使用 v3 或 v4 版本,视创建时的 CLI 选项而定。样式不生效的情况多数不是 Tailwind 本身的问题,而是content配置里没有扫描到对应目录。比如你把组件写在src/components/reusable/且文件名是.tsx,默认扫描路径却只包含./src/**/*.{ts,tsx},一般不会漏。真正容易漏的是动态拼接类名,像下面这种写法:

<div className={`bg-${color}-500`} />

这段代码在 Tailwind 编译阶段会被当作"未使用的类"修剪掉,因为编译工具不会去执行 JS 字符串拼接。解决办法是使用完整的类名映射对象,或者用safelist显式声明可能出现的类名组合。这类问题有个显著特征:样式在开发时偶尔正常、打包上线后消失,因为开发模式会保留更多候选类,生产构建则严格去重。

5.5 登录回调地址无限循环:NEXTAUTH_URL 的配置陷阱

本地开发通常不会碰到回调循环,但部署到生产环境后,NEXTAUTH_URL如果仍旧指向http://localhost:3000,登录跳转就会不断回到本地地址,或者提示 callback URL 不匹配。这个变量的值必须与部署后实际对外访问的地址一致,同时注意是否使用 HTTPS。另一个坑是反向代理场景下,NextAuth 识别到的x-forwarded-proto与真实协议不一致,导致回调地址生成错误。在容器或网关后面跑 Next.js 时,需要在环境里显式告诉 NextAuth 使用 HTTPS 协议,通常是通过AUTH_TRUST_HOST=true或自定义auth.ts中的基础路径来处理。

6. 从"能跑"到"好用":我维护 T3 Code 工程的一些体会

6.1 项目结构长期维护的几条原则

t3code模板默认的目录划分在项目初期很合理,但业务增长后我会做一些扩展。比如把 routers 按业务域拆成多个文件,每个域有自己的 zsh schema 和 service 函数,而不是把代码堆在单个 router 文件里。另一个原则是:不要在组件里直接访问ctx或数据库,组件只调用 tRPC 暴露的 procedure。这样一来,未来如果某个子模块要拆成独立服务,替换边界只发生在 router 层。对于独立开发或小团队来说,过早微服务化没有必要,但"业务逻辑和界面层分离"这件事是永远划算的。

类型定义方面,我会在src/types里补充一些跨路由共享的类型,但尽量不破坏"类型源头唯一"的原则。如果某个类型既不属于 Prisma model,又不完全等同于某个 procedure 的 input/output,那说明业务领域里有可能少了一个领域模型,值得重新审视 schema 设计。

6.2 测试策略:tRPC 项目怎么设计测试才不痛苦

tRPC 的 procedure 本质上是纯函数式调用,依赖的是ctx里的db和session。这让单元测试变得异常简单:造一个假的上下文,传入内存数据库或测试数据库,直接调用 router 里的 procedure 即可。不需要启动 HTTP 服务,也不需要 mock 网络请求。我的基本测试套件包含三块:

  • 鉴权测试:未登录调用 protectedProcedure 时是否正确抛出异常。
  • 输入校验测试:传入非法 url、空标题时,zod 是否在入口拦截。
  • 数据边界测试:用户 B 能否读取或修改用户 A 的 bookmark。

这三类测试覆盖了业务逻辑里绝大部分风险。结合 Vitest 和 Prisma 的 test 数据库,我可以在 CI 里每次提交都跑一轮。过程中最重要的一点是:测试环境的环境变量不能与开发库混用,建议在vitest.setup.ts里显式设置DATABASE_URL,避免误连真实数据库。

6.3 我最后想提醒的一件事:别为了用全而用全

t3code给我最大的启发不是"所有项目都必须套这套技术栈",而是"类型安全可以成为开发流程里的默认选项"。如果你做的只是一个快速原型、或者一个几乎没有数据交互的落地页,完全没有必要上 tRPC + Prisma + NextAuth 这套组合,直接 Vite + Tailwind 反而更轻。当你发现项目的 API 接口数量开始变多、类型两边维护不过来、鉴权逻辑重复出现时,才是切入 T3 Stack 的最佳时机。

从实际维护感受来说,这套方案在"一个人写全栈"的场景下效率提升最明显。以前我要在后端写接口、写文档,前端写类型、写请求封装;现在改一个 Prisma model,跑一次迁移,tRPC 的类型会在整个项目里自动传导,页面需要的数据直接通过 procedure 拿,中间少了大量的胶水代码。这个体验是回不去的。如果你正在搭建自己的下一个全栈项目,或者想重构一个前后端类型全靠手维护的旧工程,花一天时间把t3code的链路跑一遍,大概率能打开一扇新的大门。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/27 16:28:37

大模型FFN层中的SwiGLU激活函数与8/3*d维度缩放解析

1. 大模型FFN层中的SwiGLU激活函数解析在Transformer架构的大模型中&#xff0c;前馈神经网络&#xff08;FFN&#xff09;模块通常采用"SwiGLU"这种改进的激活函数结构。传统FFN层由两个线性变换组成&#xff0c;中间通过GELU激活函数连接&#xff0c;其标准形式可表…

作者头像 李华
网站建设 2026/10/27 16:28:34

市场技能不是发帖技巧,而是赚钱的底层操作系统

1. 这不是“学营销”&#xff0c;而是重建你和钱的关系“marketingskills”——这个词最近在招聘平台、自由职业接单群、甚至咖啡馆里年轻人的聊天中高频出现&#xff0c;但它绝不是教你怎么写朋友圈文案、怎么投信息流广告那种表层动作。我带过37个从零起步转行做私域运营的学…

作者头像 李华
网站建设 2026/10/27 16:27:05

微信小程序源码复用指南:工程切片库与调试避坑

简介&#xff1a;本资源是一套面向小程序开发者与初学者的综合性学习实践包&#xff0c;涵盖100套可直接运行的微信小程序源码&#xff0c;覆盖电商、企业官网、内容资讯、工具类及休闲小游戏等主流应用场景&#xff0c;兼顾原生开发规范与跨平台适配能力&#xff0c;适用于微信…

作者头像 李华
网站建设 2026/10/27 16:26:19

OCR技术解析:从原理到应用实践

1. 图文识别&#xff08;OCR&#xff09;技术概述图文识别&#xff08;OCR&#xff09;技术是一种将图像中的文字转换为可编辑、可搜索的文本数据的技术。这项技术最早可以追溯到20世纪初&#xff0c;当时主要用于识别邮政系统中的邮政编码。随着计算机视觉和机器学习的发展&am…

作者头像 李华
网站建设 2026/10/27 16:26:18

Unity与Pico VR手势识别实现虚拟形象骨骼控制

1. 项目背景与核心需求在虚拟现实(VR)和元宇宙应用快速发展的当下&#xff0c;如何让用户在虚拟世界中拥有自然流畅的肢体表现&#xff0c;一直是开发者面临的重要挑战。传统的手柄操作方式难以实现精细的手部动作表达&#xff0c;而基于计算机视觉的手势识别技术为这个问题提供…

作者头像 李华
网站建设 2026/10/27 16:26:02

跨境电商智能定价系统架构与实战指南

1. 跨境卖家定价痛点解析 2026年的跨境电商市场正在经历前所未有的激烈竞争&#xff0c;我最近接触的几位深圳卖家朋友都在抱怨同一个问题&#xff1a;产品定价越来越难把控。一位主营家居用品的卖家告诉我&#xff0c;他们团队每天要花3-4个小时手动核对20多个平台的同类产品价…

作者头像 李华