refactor: split tRPC build into server and react phases#26082
refactor: split tRPC build into server and react phases#26082keithwillcode merged 16 commits intomainfrom
Conversation
This change improves tRPC build performance by having the client-side code import AppRouter from pre-generated type declarations instead of traversing the entire server router tree. Changes: - Create type bridge file at packages/trpc/types/app-router.ts - Update packages/trpc/react/trpc.ts to import from the bridge - Update .gitignore to only ignore types/server (generated files) - Update eslint.config.mjs to only ignore types/server (generated files) The type bridge provides: 1. Faster typechecking - avoids parsing 458 server files 2. Stable import location that's easy to lint against 3. Single place to adjust if generated path changes Build order is already enforced in turbo.json (type-check depends on @calcom/trpc#build). Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
Move the AppRouter type bridge file from types/app-router.ts to react/app-router.ts to avoid the TS5055 'Cannot write file because it would overwrite input file' error. The issue was that placing the bridge file in types/ caused TypeScript to treat the generated .d.ts files as input files during the tRPC build, then fail when trying to emit to the same location. By placing the bridge in react/ (which is excluded from the tRPC server build), the bridge file is only used by client code and doesn't interfere with the server type generation. Changes: - Move bridge file from types/app-router.ts to react/app-router.ts - Update import in react/trpc.ts to use ./app-router - Revert .gitignore to ignore all of types/ (generated files) - Revert eslint.config.mjs to ignore all of types/** Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>
- Create tsconfig.server.json for server-only type generation - Create tsconfig.react.json for react/client type generation - Update build script to run server build first, then react build - Remove || true so build properly fails on errors - This allows react code to import from generated server types Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>
…rypoints - Remove react exports from @calcom/trpc root (index.ts) - Update 89 files to import from @calcom/trpc/react instead of @calcom/trpc - This fixes the boundary leak where server builds were pulling in react code - Server build no longer compiles react/app-router.ts, fixing the chicken-and-egg issue where react code needed generated server types that didn't exist yet This improves TypeScript build performance by preventing the server type generation from traversing the entire react/client type graph. Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>
The pre-existing Prisma type errors (~345 errors) will be addressed in a follow-up PR. This allows the two-phase build architecture changes to be merged first. Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>
There was a problem hiding this comment.
1 issue found across 1 file (changes from recent commits).
Prompt for AI agents (all issues)
Check if these issues are valid — if so, understand the root cause of each and fix them.
<file name="packages/trpc/package.json">
<violation number="1" location="packages/trpc/package.json:13">
P1: The change **adds** `|| true` to the build scripts, but the PR description states the intent is to **remove** `|| true` to properly fail on type errors. This discrepancy will cause type errors to be silently masked instead of failing the build as intended. If the goal is to surface type errors, remove `|| true`; if `|| true` is intentionally kept due to pre-existing errors (~345 mentioned in PR), update the PR description to reflect this.</violation>
</file>
Reply to cubic to teach it or ask questions. Re-run a review with @cubic-dev-ai review this PR
- Create packages/features/eventtypes/lib/schemas.ts with createEventTypeInput and EventTypeDuplicateInput - Update types.ts to re-export schemas from the new server-safe location - Update tRPC schema files to import from schemas.ts instead of types.server.ts - Delete types.server.ts (was duplicating ~200 lines unnecessarily) This keeps the server build graph clean while avoiding code duplication. Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>
There was a problem hiding this comment.
1 issue found across 7 files (changes from recent commits).
Prompt for AI agents (all issues)
Check if these issues are valid — if so, understand the root cause of each and fix them.
<file name="packages/features/eventtypes/lib/schemas.ts">
<violation number="1" location="packages/features/eventtypes/lib/schemas.ts:26">
P2: Inconsistent integer validation for `length` field. `createEventTypeInput` uses `.int()` but `EventTypeDuplicateInput` allows floats. Event lengths (minutes) should be integers in both schemas.</violation>
</file>
Reply to cubic to teach it or ask questions. Re-run a review with @cubic-dev-ai review this PR
There was a problem hiding this comment.
1 issue found across 3 files (changes from recent commits).
Prompt for AI agents (all issues)
Check if these issues are valid — if so, understand the root cause of each and fix them.
<file name="packages/trpc/package.json">
<violation number="1" location="packages/trpc/package.json:13">
P1: The PR description states `|| true` should be "temporarily kept" to handle ~345 pre-existing Prisma type errors, but this change removes it. If those type errors still exist on main, this will cause the build to fail. Either update the PR description if `|| true` is intentionally being removed, or restore it as originally planned.</violation>
</file>
Reply to cubic to teach it or ask questions. Re-run a review with @cubic-dev-ai review this PR
Per Keith's feedback, renamed the file to types.ts since it contains type definitions. Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>
E2E results are ready! |
volnei
left a comment
There was a problem hiding this comment.
Nit comments... looking good and local manual tests all ✅
| className="text-orange-600 underline" | ||
| target="_blank" | ||
| href="https://developer.paypal.com/api/rest/#link-getclientidandclientsecret"> | ||
| href="https://developer.paypal.com/api/rest/#link-getclientidandclientsecret" rel="noreferrer"> |
|
Merging on behalf of API since the only change was running trpc build:server in API v2 |
|
Love this. Great stuff :D |
* refactor: import AppRouter from generated types instead of server source This change improves tRPC build performance by having the client-side code import AppRouter from pre-generated type declarations instead of traversing the entire server router tree. Changes: - Create type bridge file at packages/trpc/types/app-router.ts - Update packages/trpc/react/trpc.ts to import from the bridge - Update .gitignore to only ignore types/server (generated files) - Update eslint.config.mjs to only ignore types/server (generated files) The type bridge provides: 1. Faster typechecking - avoids parsing 458 server files 2. Stable import location that's easy to lint against 3. Single place to adjust if generated path changes Build order is already enforced in turbo.json (type-check depends on @calcom/trpc#build). Co-Authored-By: keith@cal.com <keithwillcode@gmail.com> * fix: move bridge file to react/ to avoid TS5055 error Move the AppRouter type bridge file from types/app-router.ts to react/app-router.ts to avoid the TS5055 'Cannot write file because it would overwrite input file' error. The issue was that placing the bridge file in types/ caused TypeScript to treat the generated .d.ts files as input files during the tRPC build, then fail when trying to emit to the same location. By placing the bridge in react/ (which is excluded from the tRPC server build), the bridge file is only used by client code and doesn't interfere with the server type generation. Changes: - Move bridge file from types/app-router.ts to react/app-router.ts - Update import in react/trpc.ts to use ./app-router - Revert .gitignore to ignore all of types/ (generated files) - Revert eslint.config.mjs to ignore all of types/** Co-Authored-By: keith@cal.com <keithwillcode@gmail.com> * refactor: split tRPC build into server and react phases - Create tsconfig.server.json for server-only type generation - Create tsconfig.react.json for react/client type generation - Update build script to run server build first, then react build - Remove || true so build properly fails on errors - This allows react code to import from generated server types Co-Authored-By: keith@cal.com <keithwillcode@gmail.com> * refactor: split @calcom/trpc exports to separate server and react entrypoints - Remove react exports from @calcom/trpc root (index.ts) - Update 89 files to import from @calcom/trpc/react instead of @calcom/trpc - This fixes the boundary leak where server builds were pulling in react code - Server build no longer compiles react/app-router.ts, fixing the chicken-and-egg issue where react code needed generated server types that didn't exist yet This improves TypeScript build performance by preventing the server type generation from traversing the entire react/client type graph. Co-Authored-By: keith@cal.com <keithwillcode@gmail.com> * fix: import WorkflowType from lib/types instead of React component This fixes a boundary leak where the server build was pulling in React components through the WorkflowRepository import chain. By importing WorkflowListType from lib/types instead of WorkflowListPage.tsx, the server build no longer traverses React component files. Co-Authored-By: keith@cal.com <keithwillcode@gmail.com> * fix: extract server-safe types to prevent boundary leaks in tRPC build - Extract ChildrenEventType to lib/childrenEventType.ts (server-safe) - Extract Slots type to calendars/lib/slots.ts (server-safe) - Create types.server.ts files for eventtypes and bookings - Update server code to import from server-safe type files - Update DatePicker.tsx to use extracted Slots type - Update app-store utils to use BookerEventForAppData type This prevents the server build from pulling in React files through transitive imports from @calcom/features barrel exports. Co-Authored-By: keith@cal.com <keithwillcode@gmail.com> * fix: update Segment.test.tsx mock path to @calcom/trpc/react The test was mocking @calcom/trpc but importing from @calcom/trpc/react. After the entrypoint separation, the mock path needs to match the import path. Co-Authored-By: keith@cal.com <keithwillcode@gmail.com> * fix: temporarily restore || true to unblock PR merge The pre-existing Prisma type errors (~345 errors) will be addressed in a follow-up PR. This allows the two-phase build architecture changes to be merged first. Co-Authored-By: keith@cal.com <keithwillcode@gmail.com> * Run trpc build as part of API v2 build * Removed the bridge file * refactor: extract event type schemas to server-safe file - Create packages/features/eventtypes/lib/schemas.ts with createEventTypeInput and EventTypeDuplicateInput - Update types.ts to re-export schemas from the new server-safe location - Update tRPC schema files to import from schemas.ts instead of types.server.ts - Delete types.server.ts (was duplicating ~200 lines unnecessarily) This keeps the server build graph clean while avoiding code duplication. Co-Authored-By: keith@cal.com <keithwillcode@gmail.com> * Removed the optionality of the tRPC builds * Removed the extra command for API v2 * refactor: rename calendars/lib/slots.ts to types.ts Per Keith's feedback, renamed the file to types.ts since it contains type definitions. Co-Authored-By: keith@cal.com <keithwillcode@gmail.com> * Added back tRPC build:server for API v2 --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: Dhairyashil Shinde <93669429+dhairyashiil@users.noreply.github.com>
What does this PR do?
This PR improves tRPC build performance and correctness by:
Importing
AppRouterfrom generated types - Client-side code now importsAppRouterfrom pre-generated type declarations instead of traversing the entire server router tree (458+ files).Splitting the build into two phases - The tRPC build is now separated into
build:serverandbuild:reactcommands that run sequentially. This ensures server types are generated before the react code tries to import them.Separating server and react entrypoints -
@calcom/trpcroot no longer exports react code. All 89 consumer files have been updated to import from@calcom/trpc/reactinstead. This fixes the "boundary leak" where server builds were pulling in react code through transitive imports via@calcom/features.Changes:
packages/trpc/react/app-router.tsthat re-exportsAppRouterfrom generated typespackages/trpc/react/trpc.tsto import from the local bridge filetsconfig.server.jsonfor server-only type generation (outputs totypes/server/)tsconfig.react.jsonfor react type generation (outputs totypes/react/)package.jsonbuild script to run server build first, then react buildpackages/trpc/index.ts(now just contains comments explaining the separation)@calcom/trpc/reactinstead of@calcom/trpcTypeScript Performance Impact: By separating the entrypoints, the server type generation no longer traverses the entire react/client type graph. This should improve local DX and compilation times.
Updates since last revision
Schema extraction refactor (addressing PR review feedback):
packages/features/eventtypes/lib/schemas.tswith justcreateEventTypeInputandEventTypeDuplicateInputschemastypes.tsto re-export schemas from the new server-safe locationcreate.schema.ts,duplicate.schema.ts) to import fromschemas.tstypes.server.ts- this avoids the ~200 lines of duplication that was flagged in reviewPrevious boundary leak fixes:
WorkflowListTypefrom@calcom/ee/workflows/lib/typesinstead of from the React componentWorkflowListPage.tsxpackages/features/calendars/lib/slots.tswith server-safeSlotsandSlotInfotypespackages/features/bookings/types.server.tswith minimalBookerEventForAppDatatype for app-store utilspackages/features/eventtypes/lib/childrenEventType.tswith server-safe types@calcom/trpcto@calcom/trpc/reactLink to Devin run: https://app.devin.ai/sessions/d2c3e27efaf641a080fdb35d3ae4014c
Requested by: keith@cal.com (@keithwillcode)
Mandatory Tasks (DO NOT REMOVE)
How should this be tested?
yarn workspace @calcom/trpc build:serverto generate server types intypes/server/yarn workspace @calcom/trpc build:reactto generate react types intypes/react/yarn workspace @calcom/trpc buildto run both in sequencereact/app-router.tscan resolve../types/server/routers/_appHuman review checklist:
tsconfig.server.jsononly includes./serverand excludes./reacttsconfig.react.jsononly includes./reactand excludes./serverpackage.jsonruns server before react@calcom/trpcto@calcom/trpc/reactschemas.tscontains only zod schemas and server-safe imports (no React dependencies)types.tsre-exports fromschemas.tscorrectlyBookerEventForAppDatainbookings/types.server.tshas the required properties (price,currency,metadata)@calcom/trpcinstead of@calcom/trpc/react(potential test failures)@calcom/trpcroot no longer exports anything (breaking change for any external consumers of this internal package)|| trueChecklist