t3-oss / create-t3-turbo

Clean and simple starter repo using the T3 Stack along with Expo React Native
https://turbo.t3.gg
MIT License
4.57k stars 384 forks source link

feat: expose TRPC transformer from api package #1189

Open ochicf opened 1 week ago

ochicf commented 1 week ago

Context

In #1110, a problem with superjson caused the necessity of swapping transformer to devalue. Code for superjson is spread in 4 different places:

Currently all of those places directly import superjson, which for this specific transformer is not super problematic (as its interface matches 1 to 1 to the expected transformer in tRPC), but it makes it inconvenient to swap to another or do any customization to its behavior, as it needs to be changed in all places.

Proposal

Define the transformer in the api package and export it so it can be used in all places. Besides the benefit of applying DRY, it moves the entire responsability of the transformer where it belongs (close to the API) and the apps are just consumers.

Clarifications

Swapping transformers

Now swapping transformers will be super easy and convenient and fully transparent to developers in their local machines, though underneath it's a big breaking change as it drastically changes how the data is being sent through the API. This is why I found it necessary to add a disclaimer in that file just in case.

For example, if there are already distributed apps with the superjson transformer and there's a swap to devalue, all of those app's API calls will break when the API using devalue gets released.

Of course, this would happen before as well and it's out of the scope of this repo, but IMO as now it's easier and "seems prepared to do it" adding the disclaimer made sense.

Expo app

Including the module

To include the @acme/api/module I had to add it in the tsconfig.json's compilerOptions.paths section, pointing directly to the file.

I'm not really sure if this is correct, but it's how I managed to make it work.

Restricting usage from @acme/api package

Since the @acme/api package is now a direct dependency in the expo app, I've added some eslint rules to prevent importing values directly from it, or from modules other than /transformer.

Example of imports

/*6*/  import type { AppRouter } from "@acme/api"; // <- correct: imports type
/*7*/  import type { hello as _1 } from "@acme/api/hello"; // <- correct: imports type
/*8*/  import { createCaller as _2 } from "@acme/api"; // <- incorrect: imports value
/*9*/  import { transformer } from "@acme/api/transformer"; // <- correct: imports value from allowed module
/*10*/ import { world as _3 } from "@acme/api/world"; // <- incorrect: imports value from restricted module
[...]/create-t3-turbo/apps/expo/src/utils/api.tsx
   8:1  error  '@acme/api' import is restricted from being used. Only type imports from '@acme/api' are allowed                            @typescript-eslint/no-restricted-imports
  10:1  error  '@acme/api/world' import is restricted from being used by a pattern. Only certain modules from '@acme/api' can be imported  @typescript-eslint/no-restricted-imports

✖ 2 problems (2 errors, 0 warnings)

Requirements