Skip to content

Comments

Setup tsdown#381

Open
vio wants to merge 2 commits intomasterfrom
tsdown
Open

Setup tsdown#381
vio wants to merge 2 commits intomasterfrom
tsdown

Conversation

@vio
Copy link
Member

@vio vio commented Nov 2, 2025

  • build: tsdown setup
  • build: Remove rollup

Summary by CodeRabbit

  • Bug Fixes

    • Fixed precision calculation error in mathematical operations.
  • Chores

    • Modernized build system and updated project dependencies.
    • Restructured package exports for improved module compatibility.
    • Enhanced type definitions and improved test infrastructure.

rel: relative-ci/roadmap#70

@coderabbitai
Copy link

coderabbitai bot commented Nov 2, 2025

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

This PR migrates the project's build tooling from Rollup to tsdown. The rollup.config.mjs file is removed and replaced with a new tsdown.config.mjs configuration that defines dual-entry builds (index and extract) with both ESM and CJS output formats. The package.json exports map is restructured to use nested import/require objects with separate types and default entries. Dependencies are updated to remove Rollup-related plugins and add tsdown. Additionally, a utility function fix corrects the exponent operator in src/utils/round.ts, the src/types.ts module adds a re-exported OutputBundle type alias from Rollup, and the test file is updated to import this type from the local types module.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 3 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Setup tsdown' clearly and directly summarizes the main objective of the changeset: replacing Rollup with tsdown as the build tool.
Merge Conflict Detection ✅ Passed ✅ No merge conflicts detected when merging into master

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch tsdown

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@vio vio force-pushed the tsdown branch 3 times, most recently from 010440e to 51e6295 Compare November 2, 2025 16:51
Copy link

@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

🧹 Nitpick comments (2)
tsdown.config.mjs (1)

12-12: Consider disabling minification for library code.

Minifying library code can make debugging more difficult for consumers, as it obfuscates stack traces and makes source inspection harder even with source maps. Libraries typically ship unminified code and let consuming applications decide whether to minify.

Apply this diff to disable minification:

     format: 'esm',
     hash: false,
-    minify: true,
+    minify: false,
     sourcemap: true,
   },
   {
     outDir: 'dist/cjs',
     entry: {
       index: './src/index.ts',
       extract: './src/extract.ts',
     },
     format: 'cjs',
     hash: false,
-    minify: true,
+    minify: false,
     sourcemap: true,
   },

Also applies to: 23-23

package.json (1)

77-77: Confirm tsdown ^0.15.12 dependency management strategy.

The latest stable release is v0.15.12 (released Oct 29, 2025), and the project is under active development with frequent releases and breaking changes; users should expect API/config migrations and occasional regressions. The original concern is valid—the community recommends testing upgrades in CI or a branch before adopting in production.

Consider implementing one of the suggested approaches:

  • Pin to a specific version (e.g., "tsdown": "0.15.12") to avoid unexpected breaking changes during active development, or
  • Establish a monitoring and testing process in your CI/CD pipeline before upgrading to new tsdown releases.
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5db1a75 and dfcf548.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (4)
  • package.json (3 hunks)
  • rollup.config.mjs (0 hunks)
  • tsconfig.json (0 hunks)
  • tsdown.config.mjs (1 hunks)
💤 Files with no reviewable changes (2)
  • rollup.config.mjs
  • tsconfig.json
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Socket Security: Pull Request Alerts
🔇 Additional comments (2)
package.json (1)

4-4: Beta version is appropriate for this migration.

The version bump to 1.5.3-beta.0 correctly signals that this is a pre-release version with significant build tooling changes, allowing early testing before a stable release.

tsdown.config.mjs (1)

1-26: Now let me verify tsdown's behavior regarding automatic type declaration generation:

No action required—tsdown automatically generates type declarations.

Tsdown automatically enables declaration file generation when package.json contains a types or typings field. The package.json already specifies both "typings": "dist/esm/index.d.ts" and "types" entries in exports, so declaration file generation will be enabled by default. With TypeScript (5.9.3) installed as a devDependency, the configuration is complete and requires no changes. The absence of an explicit dts option or tsconfig.json is not a problem.

Likely an incorrect or invalid review comment.

@socket-security
Copy link

socket-security bot commented Jan 4, 2026

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Updatedrolldown@​1.0.0-rc.4 ⏵ 1.0.0-rc.3951007898100
Addedtsdown@​0.20.3981008896100

View full report

@vio vio force-pushed the tsdown branch 2 times, most recently from 2672215 to c15f463 Compare January 4, 2026 20:50
Copy link

@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: 3

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 31f0cdb and c15f463.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (4)
  • package.json
  • rollup.config.mjs
  • tsconfig.json
  • tsdown.config.mjs
💤 Files with no reviewable changes (1)
  • rollup.config.mjs
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: tests
🔇 Additional comments (4)
tsdown.config.mjs (1)

1-14: LGTM! Clean tsdown configuration for library builds.

The configuration is well-structured with appropriate settings for a library package:

  • Dual ESM/CJS output matches modern package distribution best practices
  • unbundle: true ensures all dependencies remain external
  • sourcemap: true aids debugging while minify: false keeps output readable
  • Entry points align with the package.json exports structure
tsconfig.json (1)

3-3: Good alignment with modern Node.js module resolution.

The rootDir: "." and module: "nodenext" settings properly support the new tsdown-based build workflow and dual ESM/CJS output strategy.

Also applies to: 13-13

package.json (2)

27-29: Appropriate top-level entry points for dual-package support.

The main, module, and types fields correctly establish fallback entry points for older tooling. The exports map provides more granular control for modern resolvers.


59-59: Well-structured build and testing scripts.

The migration to tsdown is clean, and the additional test:package scripts ensure compatibility across multiple bundlers (rolldown, rollup, vite). The bump/release scripts support the release workflow.

Also applies to: 63-68

Copy link

@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: 2

Fix all issues with AI Agents 🤖
In @src/utils/round.ts:
- Around line 1-4: The round function uses the bitwise XOR operator (10 ^
precision) instead of exponentiation, producing wrong multipliers; change the
multiplier calculation in round to use exponentiation (e.g., Math.pow(10,
precision) or 10 ** precision) and ensure precision is treated as an integer
(cast/validate if needed) so Math.round(value * multiplier) / multiplier returns
correct results.

In @test/unit/extract.test.ts:
- Around line 9-25: The tests currently use "as any" on rollupStats.stats which
triggers ESLint; instead give the fixture and tests proper types: declare and
export rollupStats.stats with a concrete type (e.g., export const stats:
RollupStats = ...) in the fixture (create or import a RollupStats/Stats
interface from your src types) and then update test calls from
extract(deepFreeze(rollupStats.stats as any)) to
extract(deepFreeze(rollupStats.stats)) (or if unavoidable, use rollupStats.stats
as unknown as RollupStats). Update any imports so extract, deepFreeze and
rollupStats.stats all operate on the correct typed value.
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c15f463 and 20cba36.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (7)
  • package.json
  • rollup.config.mjs
  • src/index.ts
  • src/utils/round.ts
  • test/unit/extract.test.ts
  • tsconfig.json
  • tsdown.config.mjs
💤 Files with no reviewable changes (2)
  • src/index.ts
  • rollup.config.mjs
🧰 Additional context used
🪛 GitHub Actions: ci
test/unit/extract.test.ts

[error] 9-9: ESLint: Unexpected any. Specify a different type (@typescript-eslint/no-explicit-any)

🪛 GitHub Check: lint
test/unit/extract.test.ts

[failure] 25-25:
Unexpected any. Specify a different type


[failure] 21-21:
Unexpected any. Specify a different type


[failure] 17-17:
Unexpected any. Specify a different type


[failure] 13-13:
Unexpected any. Specify a different type


[failure] 9-9:
Unexpected any. Specify a different type

🔇 Additional comments (5)
tsdown.config.mjs (1)

1-14: LGTM!

The tsdown configuration is well-structured with appropriate settings for a library: dual format output (ESM/CJS), type declarations enabled, and sourcemaps for debugging. The entry points correctly match the package.json exports.

package.json (3)

33-53: Exports structure looks correct.

The nested exports configuration properly handles both ESM and CJS consumers with their respective type declarations. The structure follows the recommended Node.js conditional exports pattern.


59-67: Good build workflow pattern.

Running type-check before tsdown ensures type errors are caught early, preventing builds with type issues. This is a solid improvement over the previous Rollup-based workflow.


88-88: tsdown version 0.18.4 is available on npm.

Version 0.18.4 exists and is a valid, published release.

tsconfig.json (1)

23-27: Declaration settings are correctly configured for the tsdown workflow.

The declaration, isolatedDeclarations, and declarationMap options alongside noEmit: true work as intended. TypeScript validates types and declaration requirements during the type-check script (which runs before the build), while tsdown with dts: true generates the actual .d.ts, .d.mts, and .d.cts files to dist/.

Copy link

@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

Fix all issues with AI Agents 🤖
In @test/unit/extract.test.ts:
- Line 1: Replace the failing direct type assertions in
test/unit/extract.test.ts by changing each "as OutputBundle" cast on the fixture
objects to the double-cast pattern "as unknown as OutputBundle" (apply this to
all five test cases where fixtures are asserted to OutputBundle) so TypeScript
accepts the intentional coercion.
🧹 Nitpick comments (1)
package.json (1)

1-109: Consider adding "type": "module" field for clarity.

A previous review suggested adding a "type": "module" field to ensure consistent module resolution. While your explicit .mjs/.cjs extensions in the exports should work, adding this field provides clarity about the package's primary module format and can help avoid edge cases with tools that rely on this field.

🔎 Suggested addition

Add near the top of package.json (e.g., after "license"):

   "license": "MIT",
+  "type": "module",
   "private": false,
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0a049b9 and 614ae93.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (6)
  • package.json
  • rollup.config.mjs
  • src/utils/round.ts
  • test/unit/extract.test.ts
  • tsconfig.json
  • tsdown.config.mjs
💤 Files with no reviewable changes (1)
  • rollup.config.mjs
🚧 Files skipped from review as they are similar to previous changes (2)
  • tsconfig.json
  • tsdown.config.mjs
🧰 Additional context used
🪛 GitHub Actions: ci
test/unit/extract.test.ts

[error] 10-10: TS2352: Conversion of type '{ 'assets/logo.abcd1234.svg': { fileName: string; type: string; source: string; }; 'assets/main.abcd1234.js': { fileName: string; type: string; code: string; modules: { '/home/user/project/src/main.js': { ...; }; '/home/user/project/src/utils.js': { ...; }; }; map: { ...; }; }; 'assets/vendors.abcd1234.js': { ...; }...' to type 'OutputBundle' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.

🪛 GitHub Check: build
test/unit/extract.test.ts

[failure] 26-26:
Conversion of type '{ 'assets/logo.abcd1234.svg': { fileName: string; type: string; source: string; }; 'assets/main.abcd1234.js': { fileName: string; type: string; code: string; modules: { '/home/user/project/src/main.js': { ...; }; '/home/user/project/src/utils.js': { ...; }; }; map: { ...; }; }; 'assets/vendors.abcd1234.js': { ...; }...' to type 'OutputBundle' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.


[failure] 22-22:
Conversion of type '{ 'assets/logo.abcd1234.svg': { fileName: string; type: string; source: string; }; 'assets/main.abcd1234.js': { fileName: string; type: string; code: string; modules: { '/home/user/project/src/main.js': { ...; }; '/home/user/project/src/utils.js': { ...; }; }; map: { ...; }; }; 'assets/vendors.abcd1234.js': { ...; }...' to type 'OutputBundle' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.


[failure] 18-18:
Conversion of type '{ 'assets/logo.abcd1234.svg': { fileName: string; type: string; source: string; }; 'assets/main.abcd1234.js': { fileName: string; type: string; code: string; modules: { '/home/user/project/src/main.js': { ...; }; '/home/user/project/src/utils.js': { ...; }; }; map: { ...; }; }; 'assets/vendors.abcd1234.js': { ...; }...' to type 'OutputBundle' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.


[failure] 14-14:
Conversion of type '{ 'assets/logo.abcd1234.svg': { fileName: string; type: string; source: string; }; 'assets/main.abcd1234.js': { fileName: string; type: string; code: string; modules: { '/home/user/project/src/main.js': { ...; }; '/home/user/project/src/utils.js': { ...; }; }; map: { ...; }; }; 'assets/vendors.abcd1234.js': { ...; }...' to type 'OutputBundle' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.


[failure] 10-10:
Conversion of type '{ 'assets/logo.abcd1234.svg': { fileName: string; type: string; source: string; }; 'assets/main.abcd1234.js': { fileName: string; type: string; code: string; modules: { '/home/user/project/src/main.js': { ...; }; '/home/user/project/src/utils.js': { ...; }; }; map: { ...; }; }; 'assets/vendors.abcd1234.js': { ...; }...' to type 'OutputBundle' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.

🔇 Additional comments (4)
src/utils/round.ts (1)

1-2: LGTM! Excellent fixes for type safety and correctness.

The explicit return type annotation improves type safety, and the exponentiation operator fix (** instead of ^) corrects the critical calculation bug.

package.json (3)

29-29: Good: Modernized types field with correct extension.

The change from "typings" to "types" follows current best practices, and the .d.cts extension correctly indicates CommonJS declaration files for dual-module packages.


35-52: LGTM! Exports properly structured for dual-module package.

The conditional exports correctly separate ESM (.mjs/.d.mts) and CJS (.cjs/.d.cts) entry points with appropriate type declarations for each condition.


59-59: Good addition: type-checking before build.

Adding a separate type-check step before tsdown ensures type errors are caught early in the build process.

Also applies to: 67-67

Copy link

@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

🤖 Fix all issues with AI Agents
In @package.json:
- Line 88: The package.json entry for the "tsdown" dependency is pointing to a
non-existent version (0.18.4); update the version string to the existing npm
release 0.14.2 by replacing "tsdown": "0.18.4" with "tsdown": "0.14.2" in
package.json so npm install succeeds.
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 614ae93 and 3feeea8.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (1)
  • package.json
🔇 Additional comments (5)
package.json (5)

4-4: LGTM: Version bump to beta is appropriate.

The minor version bump with beta tag is suitable for the build tooling migration, allowing for testing before stable release.


29-29: LGTM: CJS-first types configuration is correct.

Using the standard types field pointing to .d.cts is a valid approach for dual packages. ESM consumers will correctly resolve .d.mts through the exports map.


33-53: LGTM: Exports structure follows modern dual-package best practices.

The nested conditional exports with separate type declarations for ESM (.d.mts) and CJS (.d.cts) correctly implements the dual-package pattern. The previous issue with the "./extract" export has been resolved.


59-59: LGTM: Build script migration to tsdown is clean.

The new build workflow with type-checking before compilation is a solid approach. Running tsc first ensures type errors are caught before tsdown generates output.

Also applies to: 67-67


79-79: LGTM: Type definitions added for existing dependency.

Adding @types/deep-freeze-strict provides TypeScript support for the deep-freeze-strict package already in use.

package.json Outdated
"prettier": "3.7.4",
"release-it": "19.2.2",
"rollup": "4.54.0",
"tsdown": "0.18.4",
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

tsdown npm package latest version

💡 Result:

Latest npm release: tsdown v0.14.2 (published 13 days ago). (npmjs.com)

Citations:


Update tsdown version from 0.18.4 to 0.14.2.

tsdown version 0.18.4 does not exist on npm; the latest available version is 0.14.2. This will cause npm install to fail.

🤖 Prompt for AI Agents
In @package.json at line 88, The package.json entry for the "tsdown" dependency
is pointing to a non-existent version (0.18.4); update the version string to the
existing npm release 0.14.2 by replacing "tsdown": "0.18.4" with "tsdown":
"0.14.2" in package.json so npm install succeeds.

Copy link

@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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
package.json (2)

28-30: ⚠️ Potential issue | 🔴 Critical

Legacy fields (main, module, typings) reference stale paths.

The exports map points to ./dist/index.cjs, ./dist/index.mjs, ./dist/index.d.mts, etc., but these legacy fields still reference ./dist/cjs/index.js, ./dist/esm/index.js, and ./dist/types/index.d.ts. Consumers on older Node.js versions (or tools that fall back to main/module) will get module-not-found errors.

Proposed fix
-  "main": "./dist/cjs/index.js",
-  "module": "./dist/esm/index.js",
-  "typings": "./dist/types/index.d.ts",
+  "main": "./dist/index.cjs",
+  "module": "./dist/index.mjs",
+  "typings": "./dist/index.d.cts",

1-6: ⚠️ Potential issue | 🟡 Minor

Add "type": "module" field to package.json

The "type": "module" field is missing from the root of package.json. Since the package defines ESM exports with .mjs files, this field is needed for Node.js to properly recognize the module type. Add it after the "private" field:

"private": false,
"type": "module",
🤖 Fix all issues with AI agents
In `@package.json`:
- Line 92: The package.json contains an invalid dependency entry "tsdown":
"0.20.3"; update the package.json to use a published version (e.g., "tsdown":
"latest" or the exact version returned by running npm view tsdown versions
--json such as 0.14.2 or a valid 0.16/0.17.x release) so the dependency resolves
correctly and reinstall/update lockfile.

"release-it": "19.2.4",
"rimraf": "6.0.1",
"rollup": "4.57.1",
"tsdown": "0.20.3",
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🌐 Web query:

tsdown npm package version 0.20.3

💡 Result:

tsdown@0.20.3 does not appear to be a version you can reliably install from the npm registry.

  • The npm package page for tsdown shows the package at 0.14.2 (at the time it was crawled). [2]
  • A third-party npm-version index (Socket) shows recent versions around 0.16.x–0.17.0, with no indication of 0.20.x. [3]
  • While jsDelivr’s landing page displays “Version 0.20.3”, that conflicts with the above registry-derived version listings. [1]

What to do:

  • Install the latest published version: npm i -D tsdown@latest
  • Or verify what your npm sees: npm view tsdown version and npm view tsdown versions --json (then check whether 0.20.3 is present)

Sources: jsDelivr package page [1], npm package page [2], Socket version listing snippet [3].


Remove or replace tsdown@0.20.3—this version does not exist on npm. The npm registry shows tsdown at 0.14.2; third-party version indexes list only 0.16.x–0.17.0. Use tsdown@latest or verify the correct published version with npm view tsdown versions --json.

🤖 Prompt for AI Agents
In `@package.json` at line 92, The package.json contains an invalid dependency
entry "tsdown": "0.20.3"; update the package.json to use a published version
(e.g., "tsdown": "latest" or the exact version returned by running npm view
tsdown versions --json such as 0.14.2 or a valid 0.16/0.17.x release) so the
dependency resolves correctly and reinstall/update lockfile.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant