Skip to content

refactor: swap rollup with native rolldown (using tsdown)#6789

Merged
juliusmarminge merged 28 commits intomainfrom
tsdown
Jun 12, 2025
Merged

refactor: swap rollup with native rolldown (using tsdown)#6789
juliusmarminge merged 28 commits intomainfrom
tsdown

Conversation

@juliusmarminge
Copy link
Member

@juliusmarminge juliusmarminge commented May 27, 2025

Closes #6814
Closes #6554

trying out swapping out rollup for rolldown powered tsdown

Preview builds:

pnpm add @trpc/server@11.1.3-alpha-tmp-tsdown.44
pnpm add @trpc/client@11.1.3-alpha-tmp-tsdown.44
pnpm add @trpc/tanstack-react-query@11.1.3-alpha-tmp-tsdown.44
pnpm add @trpc/react-query@11.1.3-alpha-tmp-tsdown.44
pnpm add @trpc/next@11.1.3-alpha-tmp-tsdown.44

Summary by CodeRabbit

Summary by CodeRabbit

  • Refactor

    • Migrated build system from Rollup to tsdown across all packages for improved dual ESM/CJS output and explicit type exports.
    • Updated package exports to provide clearer import/require paths and associated type declarations.
    • Simplified and unified build scripts and configuration files for consistency.
    • Enhanced entrypoint generation to produce package.json files per entrypoint directory instead of barrel files.
  • Chores

    • Removed obsolete scripts and configuration files related to Rollup, entrypoint generation scripts, and bundle size analysis.
    • Cleaned up dependencies and updated build-related package metadata.
    • Adjusted internal tooling and configuration to align with the new build process.
    • Updated task names in turbo.json from "codegen-entrypoints" to "build".
  • Style

    • Improved consistency in output file extensions and export structure across packages.

No changes to user-facing APIs or functionality.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented May 27, 2025

Note

Currently processing new changes in this PR. This may take a few minutes, please wait...

📥 Commits

Reviewing files that changed from the base of the PR and between e3f2162 and a7f29fb.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (7)
  • examples/.test/internal-types-export/package.json (1 hunks)
  • examples/.test/internal-types-export/src/server.ts (1 hunks)
  • examples/.test/internal-types-export/tsconfig.json (1 hunks)
  • examples/.test/internal-types-export/tsdown.config.ts (1 hunks)
  • packages/server/src/@trpc/server/index.ts (3 hunks)
  • packages/server/src/unstable-core-do-not-import/initTRPC.ts (4 hunks)
  • packages/server/src/unstable-core-do-not-import/router.ts (3 hunks)
 __________________________________________________________________
< Series-A funding secured. Now, I can afford to review your code. >
 ------------------------------------------------------------------
  \
   \   \
        \ /\
        ( )
      .( o ).

Walkthrough

This update migrates the build system from Rollup (and related scripts) to tsdown across multiple packages. All Rollup configuration files, SWC dependencies, and entrypoint scripts are removed. New tsdown.config.ts files are introduced, and package exports are restructured for explicit dual ESM/CJS outputs with corresponding type declarations. Several package.json files and turbo tasks are updated to reflect these changes.

Changes

File(s) Change Summary
.vscode/settings.json Commented out the "explorer.excludeGitIgnore": true setting.
package.json; packages/client/package.json; packages/next/package.json; packages/react-query/package.json; packages/server/package.json; packages/tanstack-react-query/package.json; packages/upgrade/package.json Migrated build scripts from Rollup (and bunchee for upgrade) to tsdown. Updated main/module/types fields and restructured exports for dual ESM/CJS outputs with explicit type paths. Updated devDependencies accordingly.
packages/client/rollup.config.ts; packages/next/rollup.config.ts; packages/react-query/rollup.config.ts; packages/server/rollup.config.ts; packages/tanstack-react-query/rollup.config.ts Deleted all Rollup configuration files.
packages/client/tsdown.config.ts; packages/next/tsdown.config.ts; packages/react-query/tsdown.config.ts; packages/server/tsdown.config.ts; packages/tanstack-react-query/tsdown.config.ts; packages/upgrade/tsdown.config.ts Added tsdown configuration files specifying input sources, output formats, custom extensions, and post-build entrypoint generation logic.
packages/client/entrypoints.script.ts; packages/next/entrypoints.script.ts; packages/react-query/entrypoints.script.ts; packages/server/entrypoints.script.ts; packages/tanstack-react-query/entrypoints.script.ts Deleted entrypoint generation scripts.
packages/client/turbo.json; packages/next/turbo.json; packages/react-query/turbo.json; packages/server/turbo.json; packages/tanstack-react-query/turbo.json Renamed turbo task from "codegen-entrypoints" to "build", updating outputs as needed.
scripts/getRollupConfig.ts; scripts/analyzeSizeChange.ts Deleted Rollup and bundle analysis utility scripts.
scripts/entrypoints.ts Updated to support new package.json structure: sets main/module/types, nested exports with import/require, generates per-entrypoint package.json files, and updates turbo.json for the "build" task.
packages/server/src/unstable-core-do-not-import/http/contentType.ts Replaced use of unsetMarker symbol with a unique symbol for memoization cache sentinel.
packages/server/src/unstable-core-do-not-import/utils.ts Removed exported unsetMarker symbol; introduced branded string type alias UnsetMarker.
packages/server/tsconfig.json; tsconfig.build.json Simplified TypeScript configuration: removed explicit module/moduleResolution options and set "module" to "Preserve" in build config.
turbo.json Removed "codegen-entrypoints" task and its dependency from the "build" task.
www/docusaurus.typedoc.js Refined type annotation for package exports and adjusted extraction logic to access nested import.default fields.

Sequence Diagram(s)

sequenceDiagram
    participant Dev as Developer
    participant Tsdown as tsdown
    participant Entrypoints as entrypoints.ts
    participant Turbo as turbo.json

    Dev->>Tsdown: Run build (tsdown)
    Tsdown->>Entrypoints: onSuccess: generateEntrypoints(inputs)
    Entrypoints->>Entrypoints: Update package.json (main/module/types, exports)
    Entrypoints->>Entrypoints: Generate per-entrypoint package.json
    Entrypoints->>Turbo: Update build task outputs in turbo.json
    Entrypoints-->>Tsdown: Done
    Tsdown-->>Dev: Build complete (dual ESM/CJS outputs)
Loading

Assessment against linked issues

Objective Addressed Explanation
Ensure @trpc/server can be properly bundled with tsc + tsdown (issue #6814) Migration to tsdown build and restructuring of exports addresses bundling issues.
Provide dedicated ESM type exports for @trpc/tanstack-react-query to fix type incompatibility (issue #6554) Package.json updated with "type": "module" and dual ESM/CJS exports with explicit typings.

Assessment against linked issues: Out-of-scope changes

No out-of-scope changes detected related to the linked issues.

Suggested reviewers

  • juliusmarminge

Poem

A hop, a skip, a build anew—
Rollup hops out, tsdown hops through!
Entrypoints pruned, configs refined,
Dual outputs now so well-aligned.
With every leap, the code grows bright,
A rabbit’s cheer for builds done right!
🐇✨

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate Unit Tests
  • Create PR with Unit Tests
  • Commit Unit Tests in branch tsdown
  • Post Copyable Unit Tests in Comment

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai auto-generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@vercel
Copy link

vercel bot commented May 27, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
next-prisma-starter ✅ Ready (Inspect) Visit Preview Jun 12, 2025 10:18am
og-image ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jun 12, 2025 10:18am
www ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jun 12, 2025 10:18am

@railway-app
Copy link

railway-app bot commented May 27, 2025

🚅 Deployed to the trpc-pr-6789 environment in trpc-sse-and-websockets

Service Status Web Updated (UTC)
next-sse-chat ◻️ Removed (View Logs) Web Jun 12, 2025 at 11:16 am
next-prisma-websockets-starter ◻️ Removed (View Logs) Jun 12, 2025 at 11:16 am

@pkg-pr-new
Copy link

pkg-pr-new bot commented May 27, 2025

Open in StackBlitz

@trpc/client

npm i https://pkg.pr.new/trpc/trpc/@trpc/client@6789

@trpc/next

npm i https://pkg.pr.new/trpc/trpc/@trpc/next@6789

@trpc/react-query

npm i https://pkg.pr.new/trpc/trpc/@trpc/react-query@6789

@trpc/server

npm i https://pkg.pr.new/trpc/trpc/@trpc/server@6789

@trpc/tanstack-react-query

npm i https://pkg.pr.new/trpc/trpc/@trpc/tanstack-react-query@6789

@trpc/upgrade

npm i https://pkg.pr.new/trpc/trpc/@trpc/upgrade@6789

commit: c2e0ec0

@railway-app railway-app bot temporarily deployed to trpc-pr-6789 June 9, 2025 13:38 Destroyed
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
packages/next/turbo.json (1)

5-5: Rename codegen-entrypoints task to build. Same consolidation as other packages—see above.

🧹 Nitpick comments (4)
.vscode/settings.json (1)

32-32: Remove commented-out configuration
Commented-out settings can clutter the file. If "explorer.excludeGitIgnore" is no longer needed, please remove the line entirely; otherwise, add a clarification comment explaining why it’s disabled.

packages/client/tsdown.config.ts (1)

20-20: Consider enabling unbundle option for better tree-shaking.

The commented unbundle: true option could help address the symbol visibility issue mentioned in the PR objectives. Tree-shaking with unbundled outputs might preserve symbol visibility better than bundled outputs.

Consider testing with unbundle: true to see if it resolves the symbol hiding issue:

-  // unbundle: true,
+  unbundle: true,
packages/react-query/tsdown.config.ts (1)

17-17: Consider testing unbundle option for React components.

Similar to the client package, the unbundled option might help with the symbol visibility issue, especially important for React components where tree-shaking and export preservation are critical.

Consider enabling unbundle: true to test symbol visibility:

-  // unbundle: true,
+  unbundle: true,
packages/tanstack-react-query/tsdown.config.ts (1)

12-12: Consider unbundle option for better tree-shaking.

Consistent with other packages, enabling the unbundle option might help address the symbol visibility issues mentioned in the PR objectives.

Test with unbundled output:

-  // unbundle: true,
+  unbundle: true,
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c97573d and b382f92.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (38)
  • .vscode/settings.json (1 hunks)
  • package.json (0 hunks)
  • packages/client/entrypoints.script.ts (0 hunks)
  • packages/client/package.json (3 hunks)
  • packages/client/rollup.config.ts (0 hunks)
  • packages/client/tsdown.config.ts (1 hunks)
  • packages/client/turbo.json (1 hunks)
  • packages/next/entrypoints.script.ts (0 hunks)
  • packages/next/package.json (3 hunks)
  • packages/next/rollup.config.ts (0 hunks)
  • packages/next/tsdown.config.ts (1 hunks)
  • packages/next/turbo.json (1 hunks)
  • packages/react-query/entrypoints.script.ts (0 hunks)
  • packages/react-query/package.json (3 hunks)
  • packages/react-query/rollup.config.ts (0 hunks)
  • packages/react-query/tsdown.config.ts (1 hunks)
  • packages/react-query/turbo.json (1 hunks)
  • packages/server/entrypoints.script.ts (0 hunks)
  • packages/server/package.json (3 hunks)
  • packages/server/rollup.config.ts (0 hunks)
  • packages/server/src/unstable-core-do-not-import/http/contentType.ts (3 hunks)
  • packages/server/src/unstable-core-do-not-import/utils.ts (1 hunks)
  • packages/server/tsconfig.json (1 hunks)
  • packages/server/tsdown.config.ts (1 hunks)
  • packages/server/turbo.json (1 hunks)
  • packages/tanstack-react-query/entrypoints.script.ts (0 hunks)
  • packages/tanstack-react-query/package.json (2 hunks)
  • packages/tanstack-react-query/rollup.config.ts (0 hunks)
  • packages/tanstack-react-query/tsdown.config.ts (1 hunks)
  • packages/tanstack-react-query/turbo.json (1 hunks)
  • packages/upgrade/package.json (2 hunks)
  • packages/upgrade/tsdown.config.ts (1 hunks)
  • scripts/analyzeSizeChange.ts (0 hunks)
  • scripts/entrypoints.ts (5 hunks)
  • scripts/getRollupConfig.ts (0 hunks)
  • tsconfig.build.json (1 hunks)
  • turbo.json (1 hunks)
  • www/docusaurus.typedoc.js (2 hunks)
💤 Files with no reviewable changes (13)
  • packages/client/entrypoints.script.ts
  • packages/next/entrypoints.script.ts
  • packages/react-query/entrypoints.script.ts
  • packages/tanstack-react-query/entrypoints.script.ts
  • packages/server/entrypoints.script.ts
  • packages/next/rollup.config.ts
  • packages/client/rollup.config.ts
  • packages/tanstack-react-query/rollup.config.ts
  • packages/server/rollup.config.ts
  • package.json
  • scripts/getRollupConfig.ts
  • packages/react-query/rollup.config.ts
  • scripts/analyzeSizeChange.ts
🧰 Additional context used
🧬 Code Graph Analysis (3)
packages/server/tsdown.config.ts (1)
scripts/entrypoints.ts (1)
  • generateEntrypoints (37-150)
packages/react-query/tsdown.config.ts (1)
scripts/entrypoints.ts (1)
  • generateEntrypoints (37-150)
packages/next/tsdown.config.ts (1)
scripts/entrypoints.ts (1)
  • generateEntrypoints (37-150)
🔇 Additional comments (49)
tsconfig.build.json (1)

3-3: Verify "module": "Preserve" value
Ensure that "Preserve" (capitalized) is a valid tsc option in your TypeScript version and that it behaves as expected (i.e., keeps import/export syntax intact).

packages/tanstack-react-query/turbo.json (1)

4-4: Standardize task naming
Renaming the task from "codegen-entrypoints" to "build" aligns with other packages and consolidates the workflow. Outputs ("package.json", "dist/**") remain correct.

packages/react-query/turbo.json (1)

5-7: Standardize task naming
Replacing "codegen-entrypoints" with "build" is consistent across the monorepo, and the outputs ("package.json", "dist/**", "rsc/**", "server/**", "shared/**") accurately reflect the generated artifacts.

packages/client/turbo.json (1)

5-11: Standardize task naming
Switching to a unified "build" task matches the refactor in other packages. The outputs ("package.json", "dist/**", "links/**", "unstable-internals/**") correctly cover all client build artifacts.

packages/server/turbo.json (1)

5-5: Rename codegen-entrypoints task to build. Aligns this package’s turbo configuration with the new unified build process.

packages/server/tsconfig.json (1)

7-7: Simplify tsconfig.json: only specify target. Inherits module settings from the base config, matching the tsdown build defaults.

packages/upgrade/package.json (2)

24-24: Update build script to use tsdown. Matches the migration plan from bunchee to tsdown.


50-50: Add tsdown to devDependencies. Ensure the version (0.12.7) is consistent with other packages using tsdown.

turbo.json (1)

26-26: Drop codegen-entrypoints from root build dependencies. Aligns with the removal of the standalone codegen task across the monorepo.
Run rg "codegen-entrypoints" to confirm no residual references.

packages/server/src/unstable-core-do-not-import/http/contentType.ts (2)

28-29: Good approach for symbol scoping.

The use of Symbol.for('@trpc/server/http/memo') creates a globally registered symbol that's properly scoped to this specific use case. This is a good replacement for the removed unsetMarker import.


35-35: Consistent symbol usage across memo implementation.

The symbol comparisons and return logic are correctly updated to use the new locally-defined symbol instead of the imported unsetMarker.

Also applies to: 60-60

packages/server/src/unstable-core-do-not-import/utils.ts (1)

2-4: Good migration to branded type for compile-time safety.

Converting unsetMarker from a runtime symbol to a branded string literal type eliminates runtime overhead while maintaining type safety. This change aligns well with the migration to locally-defined symbols in dependent modules.

packages/upgrade/tsdown.config.ts (1)

3-17: Well-structured tsdown configuration for mixed output formats.

The configuration appropriately separates the binary entry (ES modules) from the transform entries (CommonJS). This makes sense given their different usage contexts - the CLI binary benefits from ES modules while transforms may need CommonJS compatibility.

packages/server/tsdown.config.ts (3)

4-20: Comprehensive entry point coverage for server package.

The input array covers all the major adapters, core modules, and utilities. This provides good coverage for the server package's public API surface.


30-33: Correct file extension mapping for dual format builds.

The outExtensions function properly maps CommonJS to .cjs/.d.cts and ES modules to .mjs/.d.mts. This follows Node.js conventions for explicit module format identification.


34-39: Appropriate entrypoint generation timing.

The onSuccess hook is the right place to trigger entrypoint generation, ensuring it only runs after successful builds. The timing logging provides useful feedback for build performance monitoring.

packages/client/tsdown.config.ts (3)

4-12: LGTM: Well-structured entry point configuration.

The entry points are logically organized, covering the main index and specific link implementations. This provides good modularity for consumers.


26-31: Good integration of entrypoint generation.

The post-build hook nicely integrates entrypoint generation into the build process, replacing the separate script approach. The timing measurement is helpful for monitoring performance.


22-25:

Details

✅ Verification successful

Verify file extension consistency across packages.

The custom file extensions follow the Node.js dual package conventions correctly. Ensure these extensions are consistently used across all migrated packages.


🏁 Script executed:

#!/bin/bash
# Description: Check for consistent file extension patterns across tsdown configs
# Expected: All configs should use the same extension mapping

echo "Checking file extension patterns in tsdown configs:"
fd "tsdown.config.ts" --exec grep -A 4 "outExtensions"

Length of output: 980


Consistent file extension mapping confirmed across all packages.

All tsdown.config.ts files use the same outExtensions logic (.d.cts/.d.mts for .d.ts and .cjs/.mjs for .js), so no changes are needed.

www/docusaurus.typedoc.js (2)

19-19: Type annotation accurately reflects new export structure.

The refined type correctly captures the nested structure with import/require fields containing default and types properties, matching the new package.json export format.


29-29:

Details

✅ Verification successful

Verify backward compatibility with string exports.

The code correctly handles both string and object exports, but ensure that existing packages with string exports continue to work during the migration period.


🏁 Script executed:

#!/bin/bash
# Description: Check if any packages still use string exports that might break
# Expected: All packages should use the new nested export structure

echo "Checking for string exports in package.json files:"
fd "package.json" packages --exec jq -r 'select(.exports != null) | .name + ": " + (.exports | to_entries[] | select(.value | type == "string") | .key)' 2>/dev/null || true

Length of output: 263


Backward compatibility with string exports verified

No packages in packages/ use string exports in their package.json. All exports follow the new nested structure, so existing imports will continue to work as expected.

packages/react-query/tsdown.config.ts (2)

4-9: Well-organized React-specific entry points.

The entry points appropriately separate concerns:

  • Main index for general usage
  • RSC for React Server Components
  • Server utilities
  • Shared components

This structure provides good modularity for different React usage patterns.


6-6:

Details

✅ Verification successful

Verify RSC file handling with .tsx extension.

Ensure that tsdown correctly processes the .tsx file for React Server Components and generates appropriate type declarations.


🏁 Script executed:

#!/bin/bash
# Description: Check if RSC files are properly configured in TypeScript config
# Expected: tsx files should be included in build configuration

echo "Checking TypeScript configuration for RSC support:"
cat packages/react-query/tsconfig.build.json | jq '.include, .compilerOptions.jsx' 2>/dev/null || echo "Could not parse tsconfig"

Length of output: 212


🏁 Script executed:

#!/bin/bash
# Locate and display the tsdown configuration for react-query package
file=$(fd tsdown.config.ts -t f 2>/dev/null | grep "packages/react-query/tsdown.config.ts")
echo "Found config at: $file"
sed -n '1,200p' "$file"

Length of output: 1027


Confirmed .tsx entry is handled correctly

I’ve verified that:

  • tsdown.config.ts explicitly lists src/rsc.tsx in its input array.
  • tsconfig.build.json includes "src" (covering all .ts and .tsx files), and leaving compilerOptions.jsx unset defaults to preserve, which still allows TypeScript to emit declaration files for TSX sources.

No further changes are needed for RSC file support—you’re all set.

packages/tanstack-react-query/tsdown.config.ts (1)

4-4: Simple and appropriate configuration.

The single entry point is suitable for this package's scope as a wrapper around TanStack React Query.

packages/tanstack-react-query/package.json (4)

3-3: Good addition of module type declaration.

Setting "type": "module" correctly establishes this as an ESM-first package, which aligns with the dual ESM/CJS output strategy.


8-10: Verify type declaration file consistency.

The main "types" field points to .d.cts (CommonJS types) while the package is declared as "type": "module". This might be intentional for backwards compatibility, but ensure this doesn't contribute to the symbol hiding issue mentioned in the PR objectives.


18-19: Migration to tsdown looks correct.

The build and dev scripts properly use tsdown instead of the previous Rollup-based approach.


27-35: Export structure correctly implements dual format support.

The nested import/require structure with separate type declarations (.d.mts for ESM, .d.cts for CJS) follows Node.js best practices for dual package exports.

packages/react-query/package.json (3)

3-3: Consistent module type declaration.

Good consistency with the ESM-first approach across packages.


28-66: Multiple entry points properly structured.

The export mapping for rsc, server, and shared entry points correctly follows the dual ESM/CJS pattern with appropriate type declarations.


114-114: Consistent tsdown version across packages.

Using the same tsdown version (0.12.7) ensures consistent build behavior across the monorepo.

packages/next/tsdown.config.ts (4)

4-11: Entry points comprehensively defined.

The input array covers all necessary entry points including app-dir modules and SSR functionality.


19-19: Investigate the commented unbundle option.

The commented unbundle: true option might be relevant to the symbol hiding issue mentioned in the PR objectives. If the previous Rollup configuration was unbundled but tsdown is bundling by default, this could cause different tree-shaking behavior.

Consider whether this option should be enabled to maintain compatibility with the previous build output:

-  // unbundle: true,
+  unbundle: true,

21-24: File extension configuration is correct.

The custom file extensions properly map CJS to .cjs/.d.cts and ESM to .mjs/.d.mts, which aligns with the package.json export structures.


25-30: Entry point generation hook properly integrated.

The onSuccess callback correctly calls the generateEntrypoints function with the input files and includes performance logging.

packages/client/package.json (2)

34-102: Complex export structure properly migrated.

The multiple export paths including links modules and unstable-internals are correctly structured with the dual ESM/CJS format. The consistent pattern across all entry points is well-maintained.


126-126:

Details

❓ Verification inconclusive

Verify the migration works end-to-end.

While the package.json changes look correct, given the symbol hiding issue mentioned in the PR objectives, ensure that all exported symbols from the client package are properly exposed in the built output.

Run the following script to compare exported symbols between the old and new build systems:


🏁 Script executed:

#!/bin/bash
# Description: Check if all expected symbols are exported in the built client package

# Build the package and check main exports
cd packages/client
npm run build

# Check if main entry point exports are accessible
node -e "
const pkg = require('./dist/index.cjs');
console.log('CJS exports:', Object.keys(pkg));
"

node -e "
import('./dist/index.mjs').then(pkg => {
  console.log('ESM exports:', Object.keys(pkg));
});
"

Length of output: 2292


Verify client build and symbol exports

The tsdown CLI isn’t installed, so npm run build currently fails and produces no dist/ output. Please install dependencies in packages/client and rerun the build:

cd packages/client
npm install
npm run build

Once the build completes, verify that dist/index.cjs and dist/index.mjs exist and expose all expected symbols:

node -e "const pkg = require('./dist/index.cjs'); console.log('CJS exports:', Object.keys(pkg));"
node -e "import('./dist/index.mjs').then(pkg => console.log('ESM exports:', Object.keys(pkg)));"
packages/server/package.json (4)

9-11:

Details

❓ Verification inconclusive

Verify the new file extension pattern alignment.

The new extension pattern (.cjs/.mjs/.d.cts) aligns with the dual-module output strategy. However, ensure that the TypeScript compiler and bundler configurations are properly set up to generate these specific extensions.


🏁 Script executed:

#!/bin/bash
# Description: Verify that tsdown config exists and produces the expected file extensions
echo "Checking for tsdown configuration..."
fd "tsdown.config" packages/server --exec cat {}

# Check if the expected output files are being generated
echo "Checking build outputs after tsdown build..."
if [ -d "packages/server/dist" ]; then
  echo "Current dist structure:"
  find packages/server/dist -name "*.cjs" -o -name "*.mjs" -o -name "*.d.cts" -o -name "*.d.mts" | head -10
fi

Length of output: 1344


Confirm build outputs match the new extension pattern
The tsdown.config in packages/server correctly maps .cjs/.mjs/.d.cts for CJS/ESM and DTS formats. Please run your build (e.g. npm run build or tsdown build) and verify that the following files are produced under packages/server/dist to align with package.json:

  • dist/index.cjs ↔ "main": "./dist/index.cjs"
  • dist/index.mjs ↔ "module": "./dist/index.mjs"
  • dist/index.d.cts ↔ "types": "./dist/index.d.cts"

If any filenames or extensions differ, update either the outExtensions in tsdown.config or the main/module/types entries in package.json to match.


3-3:

Details

✅ Verification successful

Verify the impact of adding "type": "module".

Adding "type": "module" changes how Node.js treats .js files in this package, making them ES modules by default. This is a breaking change that could affect consumers expecting CommonJS behavior.


🏁 Script executed:

#!/bin/bash
# Description: Check if any files in the codebase still use .js extensions that would be affected by the "type": "module" change
echo "Checking for .js files that might be affected by type: module..."
fd -e js . packages/server/src packages/server/dist --exec echo "Found JS file: {}"

# Check for require() calls that might break with ESM
echo "Checking for require() calls in source files..."
rg "require\(" packages/server/src -A 2

Length of output: 438


No .js files or CommonJS imports detected—"type": "module" is safe

  • Ran fd -e js packages/server/src and found zero .js files
  • Searched for require( in packages/server/src and found no matches

Adding "type": "module" will not break any existing files in this package.


197-197:

Details

❓ Verification inconclusive

Verify the @oxc-project/runtime dependency requirement.

The addition of @oxc-project/runtime suggests this is required by tsdown. Ensure this dependency is necessary and properly utilized.


🌐 Web query:

What is @oxc-project/runtime used for and is version 0.69.0 the latest stable version?

💡 Result:

Purpose of @oxc-project/runtime

@oxc-project/runtime is a package of modular runtime helpers developed as part of the OXC (JavaScript Oxidation Compiler) ecosystem. OXC is a toolkit written in Rust with the goal of providing high-performance tools for JavaScript and TypeScript, including a parser, linter, formatter, and more[1][10][7]. The runtime package is intended to supply helper functions and modules necessary for other OXC-based tools and projects, facilitating code transformation and execution tasks within modern JavaScript toolchains[2].

Developers incorporate @oxc-project/runtime to leverage these utilities when using or building upon OXC’s suite of tools, benefiting from OXC’s optimized speed and modularity.

Latest Stable Version

Version 0.69.0 is not the latest stable version. According to the official npm listing, the most recent published version is 0.72.3, released just 2 days ago as of the last update[2]. This makes 0.72.3 the newest stable release, superseding 0.69.0.

Summary Table

Purpose Latest Stable Version
Modular runtime helpers for OXC 0.72.3

For up-to-date usage or to install the package, use:

npm i @oxc-project/runtime

This ensures you receive the latest stable version and all recent improvements[2].

Citations:


🏁 Script executed:

#!/bin/bash
# Search for any references to the runtime package across the codebase
rg "@oxc-project/runtime" -n
rg "import .*@oxc-project/runtime" -n
rg "require('@oxc-project/runtime')" -n

Length of output: 515


Verify necessity and update version of @oxc-project/runtime

  • I ran searches (rg "@oxc-project/runtime", rg "import .*@oxc-project/runtime", etc.) and found no direct imports or requires in the source—only entries in the lockfile.
  • Your packages/server/package.json pins 0.69.0, but the latest stable release on npm is 0.72.3.
  • If this runtime helper is truly needed (e.g., by tsdown or another script), please confirm where it’s consumed; otherwise, remove it.
  • If you keep it, bump the version to at least ^0.72.3 to stay on the latest stable release.

28-176:

Details

❓ Verification inconclusive

Critical: Verify export structure compatibility and symbol visibility.

The exports field has been completely restructured from flat mappings to nested import/require objects. This aligns with the PR objectives mentioning symbol visibility issues. The new structure explicitly separates ESM and CJS exports, which could affect module resolution.

Given the PR objectives mention a symbol getting hidden with the new bundling approach, this export restructuring could be the cause. Please verify:


🏁 Script executed:

#!/bin/bash
# Description: Compare export availability between main and this PR branch
echo "Checking current export structure..."
node -e "console.log(Object.keys(require('./packages/server/package.json').exports))"

# Test module resolution for key exports
echo "Testing module resolution for main export..."
node -e "try { console.log('Main export resolvable:', !!require.resolve('@trpc/server')); } catch(e) { console.log('Main export error:', e.message); }"

# Check for any conditional exports that might hide symbols
echo "Checking for conditional export patterns..."
rg -A 5 -B 5 '"import":|"require":' packages/server/package.json

Length of output: 5369


🏁 Script executed:

#!/bin/bash
# Verify that the expected symbols are actually exported from the built artifacts

echo "⮕ CJS export keys from dist/index.cjs"
node -e "const pkg = require('./packages/server/dist/index.cjs'); console.log(Object.keys(pkg));"

echo
echo "⮕ ESM export keys from dist/index.mjs"
node --input-type=module -e "import pkg from './packages/server/dist/index.mjs'; console.log(Object.keys(pkg));"

Length of output: 2171


Verify import/require export visibility after restructuring

The new nested import/require form can accidentally omit symbols once built. Since the sandbox lacks built artifacts, please manually:

  • Run npm run build in packages/server and ensure dist/index.cjs and dist/index.mjs exist.
  • Inspect CJS exports:
    node -e "console.log(Object.keys(require('./packages/server/dist/index.cjs')))"
  • Inspect ESM exports:
    node --input-type=module -e "import pkg from './packages/server/dist/index.mjs'; console.log(Object.keys(pkg))"
  • Confirm that every public API symbol you expect still appears under both resolutions.
packages/next/package.json (3)

35-93: Consistent export structure across packages.

The export restructuring is consistent with the server package, which is good for maintainability. The nested import/require structure provides explicit dual-module support.

However, given the PR objectives mention symbol visibility issues, verify that all Next.js-specific exports are properly exposed.


138-138:

Details

✅ Verification successful

Verify tsdown version consistency across packages.

The tsdown version (0.12.7) should be consistent across all packages in the monorepo to avoid potential compatibility issues.


🏁 Script executed:

#!/bin/bash
# Description: Check tsdown version consistency across packages
echo "Checking tsdown versions across packages..."
rg '"tsdown":\s*"[^"]*"' packages/*/package.json

Length of output: 679


All tsdown versions are consistent across packages

All packages in the monorepo specify "tsdown": "0.12.7", so no further changes are needed.


2-2:

Details

❓ Verification inconclusive

Ensure Next.js compatibility with "type": "module".

Similar to the server package, adding "type": "module" is a significant change. For a Next.js-specific package, verify that this doesn't break Next.js applications that might expect CommonJS modules.


🏁 Script executed:

#!/bin/bash
# Description: Check for Next.js specific compatibility concerns
echo "Checking for Next.js specific files that might be affected..."
rg "next" packages/next/src -i -A 2

# Look for any Next.js configuration files that might need updates
echo "Checking for Next.js config patterns..."
fd "next.config" . --exec echo "Found Next.js config: {}"

Length of output: 16387


Double-check ESM distribution with Next.js apps

Our verification shows that packages/next itself doesn’t include a next.config.*, and all exports now live in ESM ("type": "module"). While Next.js 13+ handles ESM packages out of the box, older apps or custom servers expecting CommonJS may break. Please:

  • Test your Next.js example apps (e.g. /examples/next-minimal-starter, /examples/next-prisma-starter) to ensure they build and run without errors.
  • Verify SSR helpers (withTRPC, ssrPrepass) and App-Dir APIs import correctly in an ESM context.
  • If you still need CommonJS consumers, consider adding a CJS build or dual-package export before publishing.

No code changes required here—just confirm full compatibility in your CI/tests.

scripts/entrypoints.ts (5)

8-18: Updated PackageJson type to support new export structure.

The type updates correctly reflect the new dual-module structure with explicit import/require nested objects. This is a good foundation for the new build system.


143-144:

Details

❓ Verification inconclusive

Turbo.json task consolidation.

The change from codegen-entrypoints to build task consolidates the build process, which simplifies the pipeline. Ensure that all packages that previously had separate entrypoint generation tasks are updated accordingly.


🏁 Script executed:

#!/bin/bash
# Description: Verify turbo.json consistency across packages
echo "Checking turbo.json files across packages..."
fd "turbo.json" packages --exec sh -c 'echo "=== {} ===" && jq .tasks {}'

# Check if any old codegen-entrypoints tasks remain
echo "Checking for old codegen-entrypoints references..."
rg "codegen-entrypoints" packages/*/turbo.json || echo "No old references found"

Length of output: 517


Verify build task presence in all package-level turbo.json files

No references to codegen-entrypoints remain across your packages/*/turbo.json. Before approving, please confirm that each of these files now defines a build task under tasks (replacing the previous entrypoint generation):

• packages/client/turbo.json
• packages/next/turbo.json
• packages/react-query/turbo.json
• packages/server/turbo.json
• packages/tanstack-react-query/turbo.json

If any package is missing the build task, add it to ensure the pipeline runs as expected.


86-90:

Details

❌ Incorrect review comment

Critical: Extension change from .js to .cjs could break module resolution.

The change from .js to .cjs for CommonJS outputs is significant and could affect module resolution. Given the PR objectives mention symbol visibility issues, this could be a contributing factor.


🏁 Script executed:

#!/bin/bash
# Description: Verify that the extension changes don't break existing imports
echo "Checking for hardcoded .js imports that might break..."
rg "from ['\"]\..*\.js['\"]" packages/*/src -A 1

# Check if any consumer code expects .js extensions
echo "Checking for require() calls with .js extensions..."
rg "require\(['\"]\..*\.js['\"]" packages -A 1

# Verify that Node.js can resolve the new extensions
echo "Testing module resolution with new extensions..."
node -e "
try {
  console.log('CJS resolution test:', !!require.resolve('./packages/server/dist/index.cjs'));
} catch(e) {
  console.log('CJS resolution failed:', e.message);
}
"

Length of output: 888


Extension change to .cjs is safe and unrelated to symbol visibility fixes

I didn’t find any remaining hard-coded “.js” imports or require(“…​.js”) calls in the codebase, and with the conditional exports map pointing explicitly at “.cjs” files, Node.js will load those without issue. This change won’t impact module resolution or address symbol visibility.

Likely an incorrect or invalid review comment.


102-109:

Details

❓ Verification inconclusive

Major architectural change: Package.json files instead of barrel files.

This is a significant change from generating barrel files (index.js, index.d.ts) to generating package.json files for each entrypoint. This could be related to the symbol visibility issues mentioned in the PR objectives.

This approach may cause module resolution issues. Consider the following verification:

Consider adding a migration guide or ensuring backward compatibility for consumers who might be importing these entrypoints directly.


🏁 Script executed:

#!/bin/bash
# Description: Test if the new package.json approach works with Node.js module resolution
echo "Testing entrypoint resolution with new package.json approach..."

# Check if any existing entrypoint directories have the old barrel files
echo "Checking for old barrel files that might conflict..."
fd "index.js" packages/*/adapters packages/*/http packages/*/observable --exec echo "Found old barrel file: {}"

# Test import resolution for a specific entrypoint
echo "Testing import resolution..."
node -e "
try {
  console.log('Entrypoint resolution test:', !!require.resolve('@trpc/server/adapters/express'));
} catch(e) {
  console.log('Entrypoint resolution failed:', e.message);
}
"

Length of output: 1007


🏁 Script executed:

#!/bin/bash
# Verify existence and inspect the top of scripts/entrypoints.ts
if [ -f scripts/entrypoints.ts ]; then
  echo "scripts/entrypoints.ts found:"
  sed -n '1,200p' scripts/entrypoints.ts
else
  echo "File not found: scripts/entrypoints.ts"
fi

Length of output: 5506


Revisit module-resolution verification for per-entrypoint package.json

We’ve replaced per-directory barrel files with package.json entrypoints under each import path. Before merging, please verify in a built environment that Node’s resolver correctly picks up these package.json files:

• Ensure you run the build or call generateEntrypoints() so that each adapters/…, http/…, etc., folder contains its own package.json.
• Search for any leftover barrels (e.g. index.js, index.d.ts) in src/ to avoid conflicts:

rg 'index\.(js|d\.ts)$' -g 'src/**'

• After building, test resolution from a consumer’s perspective:

# from project root
ts-node -e "import './scripts/entrypoints';" # or your normal build
npm pack
mkdir test && cd test
npm init -y
npm install ../your-pkg-name-0.0.0.tgz
node -e "
  try {
    console.log(require.resolve('@trpc/server/adapters/express'));
  } catch (e) {
    console.error('Resolution failed:', e.message);
  }
"

• If resolution breaks for any entrypoint, consider retaining legacy barrels or documenting the change in a migration guide so downstream consumers aren’t caught off-guard.
• Finally, confirm that your published files and exports fields in the root package.json include all new subfolders.


44-53:

Details

❓ Verification inconclusive

Verify the root package export configuration.

The root package configuration has been updated to use the new extension pattern and nested export structure. Ensure the type file extensions match between import (.d.mts) and the root types field (.d.cts).

There's an inconsistency: the root types field points to .d.cts but the import types point to .d.mts. This could cause type resolution issues in ESM environments.


🏁 Script executed:

#!/bin/bash
# Description: Check if both .d.cts and .d.mts files are being generated
echo "Checking for generated type declaration files..."
fd -e "d.cts" -e "d.mts" packages/*/dist | head -10

# Verify tsdown configuration generates both formats
echo "Checking tsdown configs for type generation..."
fd "tsdown.config" packages --exec sh -c 'echo "=== {} ===" && cat {}'

Length of output: 332


🏁 Script executed:

#!/bin/bash
# Description: Check if both .d.cts and .d.mts files exist in the root dist directory
echo "Verifying generated type declaration files in root ./dist..."
fd "\.d\.(cts|mts)$" dist || echo "No .d.cts or .d.mts files found in dist/"

Length of output: 341


Verify type declaration outputs and package.json entry consistency

Ensure that your build actually emits both index.d.cts and index.d.mts files and that the fields in pkgJson point to the correct declarations:

  • Confirm that ./dist/index.d.cts and ./dist/index.d.mts exist after running the build.
  • Decide on a single “types” entry or explicitly document dual outputs:
    • If ESM consumers should use .d.mts, change
      pkgJson.types = './dist/index.d.cts';
      to
      pkgJson.types = './dist/index.d.mts';
    • If you intend to support both, add conditional exports for types or list both in types (e.g. via an object under exports['.'].types).
  • Align the root types field with the exports.import.types path to avoid resolution errors in ESM environments.

KATT
KATT previously approved these changes Jun 11, 2025
Copy link
Member

@KATT KATT left a comment

Choose a reason for hiding this comment

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

LGTM!!

AWESOME WORK

"typescript.tsdk": "node_modules/typescript/lib",
"typescript.enablePromptUseWorkspaceTsdk": true,
"explorer.excludeGitIgnore": true,
// "explorer.excludeGitIgnore": true,
Copy link
Member

Choose a reason for hiding this comment

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

classic

we could just have it off like you done here

Comment on lines +16 to +19
dts: {
sourcemap: true,
tsconfig: './tsconfig.build.json',
},
Copy link
Member

Choose a reason for hiding this comment

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

do we still have declarationMaps? 👀

... checkinggggg

Comment on lines +10 to +11
"module": "./dist/index.mjs",
"types": "./dist/index.d.cts",
Copy link
Member

@KATT KATT Jun 11, 2025

Choose a reason for hiding this comment

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

do even need these when defining exports? feels very WET but just ignore this

Copy link
Member Author

Choose a reason for hiding this comment

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

If you want to continue supporting moduleResolution: node you need it.

Removing and requiring Node16+ (nodenext, bundler etc) is a breaking change

Copy link
Member

Choose a reason for hiding this comment

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

hmmm, we are only meant to support 18+

node-start: ['18.x', '20.x']

we should never care about anything that has passed maintainence, but maybe we've been bad at setting "engines" or whatever we need in package.json

CleanShot 2025-06-12 at 01 23 24@2x

Copy link
Member Author

Choose a reason for hiding this comment

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

Unfortunately moduleResolution: node is still in use even with more modern node versions (it's a typescript setting). create-next-app shipped with it until recently 😆

For v12 we can drop both cjs and old module resolution :)

@KATT KATT mentioned this pull request Jun 11, 2025
@github-actions
Copy link
Contributor

This pull request has been locked because we are very unlikely to see comments on closed issues. If you think, this PR is still necessary, create a new one with the same branch. Thank you.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug: trpc server cannot be properly bundled with tsc + tsdown bug: Type incompatibility between @trpc/tanstack-react-query and @tanstack/react-query

2 participants