Skip to content

chore(deps): replace tsup with tsdown 0.23.1 - #1527

Merged
Anber merged 2 commits into
callstack:masterfrom
Anber:chore/replace-tsup-with-tsdown
Oct 25, 2026
Merged

Anber merged 2 commits into
callstack:masterfrom
Anber:chore/replace-tsup-with-tsdown

Conversation

@Anber

@Anber Anber commented Oct 25, 2026

Copy link
Copy Markdown
Collaborator

Summary

The tsup README says it is no longer actively maintained and recommends tsdown. @linaria/atomic, @linaria/core and @linaria/react now build dist/ with tsdown 0.23.1; the published files keep their paths, export names and module specifiers.

 // packages/core/package.json
-"build:dist": "tsup --format cjs,esm",
+"build:dist": "tsdown --format cjs,esm",
-"tsup": { "entry": ["src/index.ts", "src/processors/css.ts"], "splitting": false, "sourcemap": true, "clean": true }
+"tsdown": [  // one config per entry: 3 in atomic, 2 in core, 2 in react
+  { "entry": ["src/index.ts"], "root": "src", "sourcemap": true, "clean": true,
+    "cjsDefault": false, "dts": false, "fixedExtension": false,
+    "outputOptions": { "esModule": true, "strict": true } },
+  { "entry": ["src/processors/css.ts"], /* same options */ }
+]

 // package.json (and the `sortFirst` key in .syncpackrc.js)
-"tsup": "^7.2.0",
+"tsdown": "0.23.1",

Why each option (the tsdown defaults differ from the tsup config):

  • One config per entry, root: "src": tsdown has no splitting: false. One config for all entries emitted shared chunks (atomize-* in atomic, rolldown-runtime-* in react), which added published files and changed a testkit snapshot. root keeps dist/processors/*.
  • fixedExtension: false: without a "type" field tsdown writes .cjs, but main, exports and the hand-written processors/*.js use .js and .mjs.
  • cjsDefault: false: processors only have a default export, which tsdown would turn into module.exports = ...; the wrappers read .default.
  • dts: false: tsdown enables declarations when a manifest has types; tsc already writes types/.
  • sourcemap: true, clean: true: as before; source maps are off by default.
  • outputOptions.esModule and strict: rolldown sets __esModule only for entries with a default export and "use strict" only if the source has it; tsup always did both.
  • Exact pin: with ^0.23.1 a regenerated lockfile would take 0.23.2 (2026-10-23, under a week old).

Lockfile

  • 27 package keys added (tsdown 0.23.1 and its dependencies), 51 removed (tsup 7.2.0 and its dependencies). No package that stays changes version; rolldown stays 1.2.14 (1.2.15 is from 2026-10-21).
  • Registry dates, checked 2026-10-25: tsdown 0.23.1 on 2026-10-10; rolldown-plugin-dts 0.28.8, cac 7.1.0 and the 17 yuku packages on 2026-10-11; the other seven are older (the newest on 2026-09-18). All 27 are at least 13 days old.
  • Seven versions already locked and under a week old (astro 7.4.1, vite 8.3.5, devframe, @devframes/hub and @devframes/json-render 1.2.6, @wyw-in-js/vite and @wyw-in-js/webpack-loader 2.7.0) only get a new peer suffix in their snapshot keys.

Evidence

  • Published files from npm pack --dry-run --json in the nine published packages, after a clean forced build with tsup 7.2.0 and with tsdown: 149 files, same paths. Two clean builds of each side hash identically. The six packages that are not bundled are byte-identical.
  • 31 paths differ in content (28 dist files, 3 package.json; the manifests only in build:dist and the config key). In dist: rolldown's formatting and regenerated source maps with fewer sources; CommonJS exports are plain data properties instead of getters, with a Symbol.toStringTag of Module; comments such as the JSDoc of cx are kept; another interop helper.
  • Surface unchanged: export names, __esModule and typeof default of every entry and wrapper, and the module specifiers of all 14 dist files are identical; the 7 CommonJS files still start with "use strict"; all 14 parse as ES2022. dist/processors/styled.mjs of atomic and react cannot be imported natively in Node, before and after (resolve has no named export sync).
  • Forced build 16 tasks; core 4 tests; react 22 tests, 17 snapshots; testkit 150 passed, 2 skipped, 279 snapshots, none changed; pnpm check:all 32 tasks plus eslint and syncpack. build:dist --watch in core rebuilds dist/index.js after an edit and after the revert, keeping dist/processors/*.
# Node 24.22.0, pnpm 9.15.9
pnpm install --frozen-lockfile --ignore-scripts
pnpm install --frozen-lockfile --ignore-scripts --strict-peer-dependencies
pnpm clean && pnpm exec turbo run build --force
pnpm --filter ./packages/core test
pnpm --filter ./packages/react test
pnpm --filter ./packages/testkit test
pnpm check:all

Node floor

tsdown 0.23.1 needs Node ^22.18.0 || ^24.11.0 || >=26.0.0, narrower than engines.node >=22.12.0, which stays. The CI matrix (22.x, 24.x) is inside it; Node 22.12 to 22.17 only gets an install warning. The output language level now follows engines.node instead of the es2022 tsconfig target.

Changeset

.changeset/build-with-tsdown.md, patch for the three packages:

Switch the build of the published dist files to tsdown; the file list, the export names and the module specifiers of every entry stay the same.

Left out

  • Raising engines.node; pinning the output target.
  • A shared config module for the repeated options.
  • The six babel and tsc packages; declarations stay with tsc.

Not verified

  • A CI run of this pull request.
  • A build on Node 22.12 to 22.17 (all runs used 24.22.0).
  • The first commit alone: it still has the shared chunks; the pull request is meant to be squashed.
  • A merge with other changes to pnpm-lock.yaml, which would need the lockfile regenerated.

Anber added 2 commits October 24, 2026 23:40
tsup is no longer actively maintained and recommends tsdown. @linaria/atomic,
@linaria/core and @linaria/react now build dist/ with tsdown 0.23.1; the
tsdown options in each manifest keep the entries, the source maps, the .js
and .mjs extensions, the named CommonJS exports and the declarations from tsc.

The lockfile drops tsup 7.2.0 with esbuild 0.18.20 and @swc/core 1.3.20 and
adds tsdown 0.23.1, which reuses the locked rolldown 1.2.14.
…S markers

tsup ran with `splitting: false`, which tsdown does not have, so one build of
all entries moved the atomize helper of @linaria/atomic and the CommonJS
interop runtime of @linaria/react into shared chunks with hashed names. Each
manifest now lists one tsdown config per entry with `root: "src"`, so every
entry is bundled on its own as before and dist/ has the same files.

`outputOptions.esModule: true` keeps `__esModule` on the CommonJS entries that
have no default export, and `outputOptions.strict: true` keeps the
"use strict" directive at the top of every CommonJS file, as tsup wrote them.
@changeset-bot

changeset-bot Bot commented Oct 25, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: a296be1

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 9 packages
Name Type
@linaria/atomic Patch
@linaria/core Patch
@linaria/react Patch
@linaria/babel-plugin-interop Patch
linaria Patch
@linaria/postcss-linaria Patch
@linaria/server Patch
@linaria/stylelint-config-standard-linaria Patch
@linaria/stylelint Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@Anber
Anber merged commit 1f2df81 into callstack:master Oct 25, 2026
4 checks passed
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