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

2023年 10月 11日 69.9k 0

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

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

创建示例项目

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

server

  • server 安装依赖 pnpm i typescript @trpc/server zod
  • 创建tsconfig.json文件,我们制定编译后js代码的输出路径为./dist,类型声明的输出路径为./types,strict必须设置为true。
  • {
      "compilerOptions": {
        "composite": true,
        "strict": true,
        "outDir": "./dist",
        "declarationDir": "./types",
        "removeComments": false
      },
      "include": ["./"]
    }
    
  • 复制官方实例,简单写一个trpc程序
  • 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);
    
  • 然后直接运行tsc,编译整个项目。得到编译后文件types/index.d.ts文件,
  • client

  • 先安装依赖pnpm install typescript @trpc/client
  • 把server发包有点麻烦了,这里为了方便我们直接使用pnpm link ../server直接模拟安装了server的依赖(lotus-trpc-server),npm也可以直接把gihub的仓库当成依赖,不需要发包。
  • image.png

  • 照着官方示例写点代码,并且AppRouter的类型从server获取
  • 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({
      links: [
        httpBatchLink({
          url: 'http://localhost:3000',
        }),
      ],
    });
    
    trpc.test
      .query({})
      .then((res) => {})
      .catch((err: ErrorShape) => {});
    
    
  • 让我们来检验一下成果
  • image.png

    image.png

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

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

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

    其他

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

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

    使用前:

    image.png
    使用后:

    image.png

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

    }0I6OV66BZQ4LZ4$T~M@9_8.gif

    相关文章

    JavaScript2024新功能:Object.groupBy、正则表达式v标志
    PHP trim 函数对多字节字符的使用和限制
    新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
    使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
    为React 19做准备:WordPress 6.6用户指南
    如何删除WordPress中的所有评论

    发布评论