Skip to content

Comments

refactor: split tRPC build into server and react phases#26082

Merged
keithwillcode merged 16 commits intomainfrom
devin/1766249341-fix-approuter-import-from-generated-types
Dec 21, 2025
Merged

refactor: split tRPC build into server and react phases#26082
keithwillcode merged 16 commits intomainfrom
devin/1766249341-fix-approuter-import-from-generated-types

Conversation

@keithwillcode
Copy link
Contributor

@keithwillcode keithwillcode commented Dec 20, 2025

What does this PR do?

This PR improves tRPC build performance and correctness by:

  1. Importing AppRouter from generated types - Client-side code now imports AppRouter from pre-generated type declarations instead of traversing the entire server router tree (458+ files).

  2. Splitting the build into two phases - The tRPC build is now separated into build:server and build:react commands that run sequentially. This ensures server types are generated before the react code tries to import them.

  3. Separating server and react entrypoints - @calcom/trpc root no longer exports react code. All 89 consumer files have been updated to import from @calcom/trpc/react instead. This fixes the "boundary leak" where server builds were pulling in react code through transitive imports via @calcom/features.

Changes:

  • Create type bridge file at packages/trpc/react/app-router.ts that re-exports AppRouter from generated types
  • Update packages/trpc/react/trpc.ts to import from the local bridge file
  • Create tsconfig.server.json for server-only type generation (outputs to types/server/)
  • Create tsconfig.react.json for react type generation (outputs to types/react/)
  • Update package.json build script to run server build first, then react build
  • Remove react exports from packages/trpc/index.ts (now just contains comments explaining the separation)
  • Update 89 files to import from @calcom/trpc/react instead of @calcom/trpc

TypeScript 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):

  • Created packages/features/eventtypes/lib/schemas.ts with just createEventTypeInput and EventTypeDuplicateInput schemas
  • Updated types.ts to re-export schemas from the new server-safe location
  • Updated tRPC schema files (create.schema.ts, duplicate.schema.ts) to import from schemas.ts
  • Deleted types.server.ts - this avoids the ~200 lines of duplication that was flagged in review

Previous boundary leak fixes:

  • WorkflowRepository.ts: Import WorkflowListType from @calcom/ee/workflows/lib/types instead of from the React component WorkflowListPage.tsx
  • Slots type extraction: Created packages/features/calendars/lib/slots.ts with server-safe Slots and SlotInfo types
  • BookerEvent type extraction: Created packages/features/bookings/types.server.ts with minimal BookerEventForAppData type for app-store utils
  • ChildrenEventType extraction: Created packages/features/eventtypes/lib/childrenEventType.ts with server-safe types
  • Segment.test.tsx fix: Updated mock path from @calcom/trpc to @calcom/trpc/react

Link to Devin run: https://app.devin.ai/sessions/d2c3e27efaf641a080fdb35d3ae4014c
Requested by: keith@cal.com (@keithwillcode)

Mandatory Tasks (DO NOT REMOVE)

  • I have self-reviewed the code (A decent size PR without self-review might be rejected).
  • I have updated the developer docs in /docs if this PR makes changes that would require a documentation change. N/A - internal build optimization.
  • I confirm automated tests are in place that prove my fix is effective or that my feature works. N/A - build/type system change verified by CI.

How should this be tested?

  1. Run yarn workspace @calcom/trpc build:server to generate server types in types/server/
  2. Run yarn workspace @calcom/trpc build:react to generate react types in types/react/
  3. Or run yarn workspace @calcom/trpc build to run both in sequence
  4. Verify the bridge file at react/app-router.ts can resolve ../types/server/routers/_app

Human review checklist:

  • Verify tsconfig.server.json only includes ./server and excludes ./react
  • Verify tsconfig.react.json only includes ./react and excludes ./server
  • Confirm build order in package.json runs server before react
  • Spot-check a few of the 89 import changes from @calcom/trpc to @calcom/trpc/react
  • Verify schemas.ts contains only zod schemas and server-safe imports (no React dependencies)
  • Verify types.ts re-exports from schemas.ts correctly
  • Verify BookerEventForAppData in bookings/types.server.ts has the required properties (price, currency, metadata)
  • Check for any other test files that mock @calcom/trpc instead of @calcom/trpc/react (potential test failures)
  • Understand that @calcom/trpc root no longer exports anything (breaking change for any external consumers of this internal package)
  • Plan follow-up PR to fix pre-existing Prisma type errors and remove || true

Checklist

  • My code follows the style guidelines of this project
  • I have commented my code, particularly in hard-to-understand areas
  • I have checked if my changes generate no new warnings

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-integration
Copy link
Contributor

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR that start with 'DevinAI' or '@devin'.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

@vercel
Copy link

vercel bot commented Dec 20, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

3 Skipped Deployments
Project Deployment Review Updated (UTC)
cal Ignored Ignored Dec 21, 2025 1:39am
cal-companion Ignored Ignored Preview Dec 21, 2025 1:39am
cal-eu Ignored Ignored Dec 21, 2025 1:39am

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>
@keithwillcode keithwillcode self-assigned this Dec 20, 2025
@keithwillcode keithwillcode marked this pull request as ready for review December 20, 2025 17:27
@keithwillcode keithwillcode enabled auto-merge (squash) December 20, 2025 17:27
@graphite-app graphite-app bot added the core area: core, team members only label Dec 20, 2025
@graphite-app graphite-app bot requested a review from a team December 20, 2025 17:27
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 2 files

volnei
volnei previously approved these changes Dec 20, 2025
- 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>
@devin-ai-integration devin-ai-integration bot changed the title refactor: import AppRouter from generated types instead of server source refactor: split tRPC build into server and react phases Dec 20, 2025
…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>
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

@keithwillcode keithwillcode requested a review from a team as a code owner December 21, 2025 01:04
- 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>
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 &quot;temporarily kept&quot; 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

devin-ai-integration bot and others added 2 commits December 21, 2025 01:28
Per Keith's feedback, renamed the file to types.ts since it contains type definitions.

Co-Authored-By: keith@cal.com <keithwillcode@gmail.com>
@github-actions
Copy link
Contributor

E2E results are ready!

Copy link
Contributor

@volnei volnei left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unrelated but cool!!

@keithwillcode
Copy link
Contributor Author

Merging on behalf of API since the only change was running trpc build:server in API v2

@keithwillcode keithwillcode merged commit 51bce67 into main Dec 21, 2025
42 checks passed
@keithwillcode keithwillcode deleted the devin/1766249341-fix-approuter-import-from-generated-types branch December 21, 2025 02:43
@hbjORbj
Copy link
Contributor

hbjORbj commented Dec 21, 2025

Love this. Great stuff :D

Anshumancanrock pushed a commit to Anshumancanrock/cal.com that referenced this pull request Jan 12, 2026
* 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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants