因为不用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了吧,都给我狠狠的用!

相关推荐
ci0n4 天前
PVE 网卡冗余配置
全栈
不想说话的麋鹿5 天前
「项目实战」从0搭建NestJS后端服务(八):静态资源访问以及文件上传
前端·node.js·全栈
hboot8 天前
rust 全栈应用框架dioxus
前端·rust·全栈
林夕11208 天前
Node.js Web开发进阶:Stream、HTTP模块与文件上传全解析
前端·node.js·全栈
天天扭码8 天前
用一个项目揭开AI全栈的神秘面纱——让AI根据你的项目数据生成回答
openai·ai编程·全栈
Edward-tan9 天前
【玩转全栈】—— Django+vue3+讯飞星火API 实现前端页面实时AI答复
vue3·全栈·django5
小鬼难缠z9 天前
阿里云部署Hugo与备案实践
程序员·全栈
南囝coding10 天前
独立开发者工具 • 半月刊 • 第 008 期
产品·全栈·设计
深度学习机器19 天前
SmolDocling-256M:极小参数量的视觉语言模型|端到端文档解析方案的另一种思路
人工智能·产品·全栈
404BrainNotFound21 天前
Dokploy部署Net服务,打造CI/CD开发环境
运维·全栈