In #1110, a problem with superjson caused the necessity of swapping transformer to devalue. Code for superjson is spread in 4 different places:
packages/api/src/trpc.ts
apps/nextjs/src/trpc/query-client.ts
apps/nextjs/src/trpc/react.tsx
apss/expo/src/utils/api.tsx
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)
Context
In #1110, a problem with
superjson
caused the necessity of swapping transformer todevalue
. Code forsuperjson
is spread in 4 different places:packages/api/src/trpc.ts
apps/nextjs/src/trpc/query-client.ts
apps/nextjs/src/trpc/react.tsx
apss/expo/src/utils/api.tsx
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 todevalue
, all of those app's API calls will break when the API usingdevalue
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 thetsconfig.json
'scompilerOptions.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
packageSince 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
Requirements