因为不用monorepo而放弃tRPC?教你如何在前后端分开项目中使用tRPC

之前写过一篇关于tRPC的文章 还在前后端分离?来试试tRPC与Next.js吧! - 掘金 (juejin.cn),评论里有同学问在前后端分离的项目中可以使用吗,钻研了一下在前后端分开的项目中的如何使用trpc。

最简单的方式应该直接把server上传为包(没试过),然后让客户端安装就行,但是这样可能会让一些自动生成的类型的库无效比如prisma。所以还得优化一下

创建示例项目

首先先创建两个仓库的文件,client和server,执行pnpm init初始化项目,都创建一个index.ts文件

server

  1. server 安装依赖 pnpm i typescript @trpc/server zod
  2. 创建tsconfig.json文件,我们制定编译后js代码的输出路径为./dist,类型声明的输出路径为./types,strict必须设置为true。
json 复制代码
{
  "compilerOptions": {
    "composite": true,
    "strict": true,
    "outDir": "./dist",
    "declarationDir": "./types",
    "removeComments": false
  },
  "include": ["./"]
}
  1. 复制官方实例,简单写一个trpc程序
ts 复制代码
import { initTRPC } from '@trpc/server';
import { z } from 'zod';
import { createHTTPServer } from '@trpc/server/adapters/standalone';

const t = initTRPC.create();
export const router = t.router;
export const publicProcedure = t.procedure;

const appRouter = router({
  /** 这是测试!! */
  test: publicProcedure
    .input(
      z.object({
        field1: z.number(),
        field2: z.string(),
      }),
    )
    .query(async () => {
      return {
        date: new Date(),
        number: 1,
        string: 1,
        nested: {
          a: 1,
        },
        array: [],
      };
    }),
});

export type AppRouter = typeof appRouter;

const server = createHTTPServer({
  router: appRouter,
});

server.listen(3000);
  1. 然后直接运行tsc,编译整个项目。得到编译后文件types/index.d.ts文件,

client

  1. 先安装依赖pnpm install typescript @trpc/client
  2. 把server发包有点麻烦了,这里为了方便我们直接使用pnpm link ../server直接模拟安装了server的依赖(lotus-trpc-server),npm也可以直接把gihub的仓库当成依赖,不需要发包。
  1. 照着官方示例写点代码,并且AppRouter的类型从server获取
ts 复制代码
import { createTRPCProxyClient, httpBatchLink } from '@trpc/client';
import type { AppRouter } from 'lotus-trpc-server/types'; // 从后端拿到的AppRouter
type ErrorShape = AppRouter['_def']['_config']['$types']['errorShape'];

const trpc = createTRPCProxyClient<AppRouter>({
  links: [
    httpBatchLink({
      url: 'http://localhost:3000',
    }),
  ],
});

trpc.test
  .query({})
  .then((res) => {})
  .catch((err: ErrorShape) => {});
  1. 让我们来检验一下成果

可以看到catch这里我搞了个骚操作,把后端的error类型拿到了。

后端的注释文档也是正常显示的

ok,一切运行正常,非常完美!在我的另一个使用prisma的项目中也进行了测试,可以正常拿到prisma的类型。

其他

可能会有人觉得ts的类型有时候不够直观,完全看不出要传什么 可以参考一下这个类型工具,可以把ide提示的字段扩展开,更直观看到有什么字段visual studio code - How can I see the full expanded contract of a Typescript type? - Stack Overflow

ts 复制代码
export type Expand<T> = T extends (...args: infer A) => infer R
  ? (...args: Expand<A>) => Expand<R>
  : T extends infer O
  ? { [K in keyof O]: O[K] }
  : never;

export type ExpandRecursively<T> = T extends (...args: infer A) => infer R
  ? (...args: ExpandRecursively<A>) => ExpandRecursively<R>
  : T extends object
  ? T extends infer O
    ? { [K in keyof O]: ExpandRecursively<O[K]> }
    : never
  : T;

使用前:

使用后:

这下没有理由不使用tRPC了吧,都给我狠狠的用!

相关推荐
半旧51817 天前
cursor重构谷粒商城02——30分钟构建图书管理系统【cursor使用教程番外篇】
java·重构·全栈·cursor·谷粒商城·全栈项目
进击的七崽1 个月前
Next入门?看这一篇就够了
全栈·next.js
codexu1 个月前
Tauri 开源笔记(3) - 本地数据存储
前端·开源·全栈
黑羽同学1 个月前
理解Nuxt——基于Nuxt SSG纯前端实现游戏官网(SEO)
vue.js·全栈·nuxt.js
余生H1 个月前
前端Python应用指南(二)深入Flask:理解Flask的应用结构与模块化设计
前端·后端·python·flask·全栈
梦兮林夕2 个月前
Next.js 技术选型攻略:最佳实践与工具推荐
前端·全栈·next.js
梦兮林夕2 个月前
提升用户体验:Next.js 中的 Loading UI 和流式渲染
前端·全栈·next.js
Xiaobaiforgod2 个月前
后端技术进阶知识总结
前端·后端·ai·大模型·llm·全栈
moonless02222 个月前
【GISer精英计划_06】WebGIS全栈技术核心以防汛系统为例
websocket·gis·全栈
竺梓君2 个月前
JavaScript内存管理机制解析
javascript·全栈