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

相关推荐
AAA阿giao15 小时前
用 AI 工程师 Trae Solo ,一个人打造“绘本岛”:从想法到上线只需三步
人工智能·全栈·trae
浪遏3 天前
好久不见 ,甚是想念 | vibe coding 一个react native 全栈项目| 小账兜
react native·全栈·vibecoding
前端小万5 天前
芋道实战|34k开源项目如何新建模块?
全栈
Mintopia9 天前
🧠 Next.js × GraphQL Yoga × GraphiQL:交互式智能之门
前端·后端·全栈
笛秋白9 天前
快速了解搭建网站流程——全栈网站搭建指南
团队开发·web·web开发·全栈·网站开发
lichenyang45310 天前
Next.js 学习笔记:从约定式路由到 Tailwind、Image、Font 优雅整合。
前端·javascript·全栈
Mintopia10 天前
🌐 《GraphQL in Next.js 初体验》中文笔记
前端·后端·全栈
Mintopia11 天前
🚀 一文看懂 “Next.js 全栈 + 微服务 + GraphQL” 的整体样貌
前端·javascript·全栈
不想说话的麋鹿11 天前
「项目前言」从配置程序员到动手造轮子:我用Vue3+NestJS复刻低代码平台的初衷
前端·程序员·全栈
Mintopia12 天前
🚀 Next.js 压力测试与性能调优实战
前端·javascript·全栈