Skip to content

Investigate migrating from unmaintained tsup to tsdown #1492

Closed

Description

@cliffhall

Background

The CLI and TUI clients (and test-servers) currently bundle with tsup, which is effectively unmaintained. tsdown is the actively-maintained, Rolldown-powered successor positioned as a drop-in replacement.

Goal

Investigate why we're on tsup and evaluate migrating to tsdown.

Tasks

  • Inventory every place tsup is used (clients/cli, clients/tui, test-servers, any others) and the config/options each relies on.
  • Assess tsdown compatibility with those configs (entry points, formats, dts, externals, the @inspector/core alias, watch mode).
  • Prototype the migration for one client and confirm builds + tests pass.
  • Document findings and recommend whether/how to migrate.

Acceptance criteria

  • A clear recommendation on migrating to tsdown, with the migration path and any blockers identified.

Activity

  1. self-assigned this
    on Jun 15, 2026
  2. added this to the v2.2.0 milestone on Jul 28, 2026
  3. removed their assignment
    on Aug 1, 2026
  4. cliffhall commented on Aug 1, 2026

    @cliffhall
    MemberAuthor

    Triage: Priority = Medium

    Scored 6/16 with the priority rubric added to AGENTS.md in #1891. This card is already approved and sitting in Todo — only Priority was set here, its Status is unchanged.

    Axis Score Reasoning
    Severity / impact 2/5 Build tooling hygiene. tsup is effectively unmaintained but nothing is broken; this is an investigation whose outcome may legitimately be 'stay'.
    Urgency / staleness 3/5 v2.2.0 milestone. No forcing function beyond the maintenance risk of sitting on an unmaintained bundler.
    Signal bonuses +1 milestone (v2.2.0) (+1)
    Total 6 Lands in the Medium band (6-8).

    Related issues. One connected issue:

    Scores are a starting point, not a verdict — the rubric is meant to be overruled when it's plainly wrong, provided the reason is written down.

  5. added
    choreMaintenance: deps, build tooling, CI, cleanup — no user-facing behavior change
    on Aug 5, 2026
  6. modified the milestones: v2.2.0, v2.3.0, v2.4.0 on Aug 10, 2026
  7. modified the milestones: v2.4.0, v2.5.0, v2.6.0 on Aug 23, 2026
  8. removed this from the v2.6.0 milestone on Sep 6, 2026
  9. 7 remaining items

  10. modified the milestones: v2.10.0, v2.11.0 on Oct 5, 2026
  11. modified the milestones: v2.11.0, v2.12.0 on Oct 12, 2026
  12. modified the milestones: v2.12.0, v2.13.0 on Oct 20, 2026
  13. FelixFangX commented on Oct 20, 2026

    @FelixFangX

    I tried this locally on v2/main (d0714d5) with tsdown 0.23.1 (Rolldown 1.2.13), migrating all four tsup builds: clients/cli, clients/tui, clients/mcpdo (two entries) and clients/web/tsup.runner.config.ts. All four build and --help works on each binary. The cli, mcpdo and tui test suites, scripts/verify-bundle-externals and the smoke:* scripts pass, and every package emits the same set of bare imports as with tsup. I didn't run the full web suite, pack:verify or local:gate.

    The config mapping is mostly mechanical. Common shape:

    export default defineConfig({
      entry: { index: "src/index.ts" },
      format: ["esm"], platform: "node", target: "node22",
      outDir: "build", clean: true, sourcemap: false, dts: false,
      fixedExtension: false,
      alias: { "@inspector/core": path.join(repoRoot, "core") },
      deps: {
        alwaysBundle: [/^@inspector\/core/],
        neverBundle: EXTERNALS.flatMap((name) => [name, new RegExp(`^${name}(?:/|$)`)]),
      },
      outputOptions: { comments: { jsdoc: false } },
    });

    The esbuild alias callbacks become a plain alias. noExternal/external become deps.alwaysBundle/deps.neverBundle (the old names still work but are deprecated). The TUI also needs inputOptions: { transform: { jsx: { runtime: "automatic" } } } and ink-form/ink-scroll-view in alwaysBundle. Shebangs are kept and tsdown sets the exec bit itself, so no banner is needed.

    Gotchas, none of which fail the build:

    1. A plain string in neverBundle only matches the exact id, so subpaths like zod/v4, @modelcontextprotocol/client/stdio and react/jsx-runtime got inlined (the CLI grew to 1.9 MB, the TUI to 2.1 MB). That's why the config adds a regex per name. tsdown prints "Detected dependencies in bundle", but the build still succeeds.
    2. Output defaults to .mjs. fixedExtension: false keeps index.js/mcpdod.js, which e2e.test.ts, mcpdo/src/daemon/ensure.ts and pack-and-verify.mjs expect.
    3. Rolldown keeps JSDoc comments, so the CLI bundle came out at 1.18 MB vs 877 KB with tsup. With comments: { jsdoc: false } it's 658 KB (I only checked that on the CLI).
    4. scripts/verify-bundle-externals.mjs depends on tsup's output and config. It looks for esbuild's // path banners, but Rolldown writes //#region path, so it fails with "has no esbuild module banners". It also parses external: [ from the config text, and its test discovers tsup*.config.ts. clients/tui/__tests__/tsupConfig.test.ts imports the tsup config and its Options type. All of these need small updates, as do the config names in the tsconfig includes and in scripts/sdk-watch.mjs.

    I'd migrate. The per-client change is small, and the externals guard catches the one subtle part once it understands Rolldown's region comments. Suggested order: CLI first (single entry, with an e2e test on the built binary), then the web runner and mcpdo, then the TUI (JSX plus the React externals policy test).

  14. modified the milestones: v2.13.0, v2.14.0 on Oct 25, 2026
  15. self-assigned this
    on Oct 25, 2026
  16. cliffhall commented on Oct 25, 2026

    @cliffhall
    MemberAuthor

    Shipped in #2803 (merged to v2/main as c621b99). Recommendation: migrate. The CLI is on tsdown now; the remaining builds are tracked in #2797.

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

Metadata

Metadata

Assignees

Labels

choreMaintenance: deps, build tooling, CI, cleanup — no user-facing behavior changev2Issues and PRs for v2

Type

No type

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions