ts-r-build

Bundler and minifier. Replaces esbuild, Rollup, Vite build.

  • Alpha
  • On npm

ts-r-build bundles and minifies TypeScript and JavaScript for production. Its command line follows esbuild 0.28.2, so most esbuild commands work after swapping the binary name. Like esbuild, it strips types without checking them.

What switching looks like

ts-r-build reads the config you already have, so switching is a change to the command, not the project.

package.json
  "scripts": {
-   "build": "esbuild src/app.ts --bundle --minify --outdir=dist",
+   "build": "ts-r-build src/app.ts --bundle --minify --outdir=dist",
  }

What works, and what doesn’t yet

Works today

  • Bundling ES modules and CommonJS, with tree shaking that honours sideEffects and /*#__PURE__*/
  • Output formats esm, cjs and iife, and code splitting with --splitting
  • Platforms browser, node and neutral; tsconfig paths and baseUrl
  • Minification of whitespace, identifiers and syntax
  • Source maps: linked, external, inline or both
  • JSX with the classic or the automatic runtime, --watch and a persistent build cache

Not yet

  • No plugins and no JavaScript config file or API
  • No CSS bundling; @import is not followed
  • No lowering below ES2015: const, classes and destructuring are errors at --target=es5
  • No --mangle-props, --drop, --pure or --keep-names

Measured

Every run, on the same pinned public projects as the home page, with the command and commit that recorded it.

ts-r-build against esbuild 0.28.2 on a dedicated Linux machine

three.js x10 (ten copies of three.js, minified IIFE with source maps) on four dedicated Linux cores, from the review box's bench of pull request #42 on 2026-10-24: these are the numbers in the README's benchmark table. Both bundlers produce the same exports from the same input. Without its persistent cache ts-r-build took 962.9 ms against esbuild's 1,409.8 ms; with the cache, 484.6 ms. The shared-laptop runs below are older (commit 2fb2555), and there the two were level without the cache. Peak memory and excalidraw were not measured on this run.

Bundle three.js x10, minifiedShorter is faster, in ms
  • ts-r
  • Other tools
  • esbuild 0.28.21,409.8 ms
  • ts-r-build, persistent cache484.6 ms
  • ts-r-build, no cache962.9 ms
How we measured
Measured
Wall time of whole processes with hyperfine (cargo xtask bench --repos three-x10), median of 10 runs after 2 warm-ups; peak memory not measured on this run
Machine
Linux x86-64: four cores of the review box's bench machine, a cpuset nothing else is scheduled on while it measures (one bench slot); release build. The CPU model is not recorded with the result
Software
ts-r-build release build of PR #42's head d8a6a97 (merged as 8b6c630), benchmarked against main at 0697824: the two differ only in ts_r_run, which no scenario here runs, with --threads=4; esbuild 0.28.2 pinned in bench/package.json, with its default threads
Input
three.js x10 at the commit pinned in bench/repos.toml (bench/entry.js, minified IIFE with source maps)
Command
The review box's pull request bench (bench.yml): cargo xtask bench --repos trpc,date-fns,rxjs,three-x10
Recorded in
commit 1a20ed6

ts-r-build against esbuild 0.28.2 on the shared laptop

Bundling two public projects on the shared laptop, with older code than the Linux run above: three.js x10 (ten copies of three.js, minified IIFE with source maps) and the excalidraw app (minified ESM). Only three.js x10 is drawn as bars: both bundlers produce the same exports from the same input. At commit 2fb2555, without its persistent cache, ts-r-build was about as fast as esbuild there: three invocations of 10 runs each gave medians of 231.8, 233.9 and 255.0 ms against esbuild's 262.7, 238.5 and 246.2 ms, so esbuild was faster in the last one, which the bars show. On excalidraw ts-r-build does less work than esbuild: it does not bundle template-literal import() yet, so it leaves out the 61 locale chunks esbuild emits (7.2 MB of output against 9.3 MB). Those runs, the single bundle and the 20 rebuilds, are in the table with that note, not drawn next to esbuild. Rolldown and Vite's production build have not been measured.

Bundle three.js x10, minifiedShorter is faster, in ms
  • ts-r
  • Other tools
  • esbuild 0.28.2246.2 ms
  • ts-r-build, persistent cache132.2 ms
  • ts-r-build, no cache255 ms
excalidraw (not like-for-like), memory, output and the oracle
Whatts-r-buildesbuild 0.28.2Notes
Bundle excalidraw, minified: no cache / persistent cache255 / 132 ms201 msMedian of 10 runs. Not like-for-like: ts-r-build leaves out the 61 locale chunks esbuild emits (7.2 MB of output against 9.3 MB)
excalidraw: first build plus 20 edit-and-rebuild cycles, one process1,358 ms3,457 ms (context.rebuild)Median of 5 runs. Not like-for-like: every build leaves out the 61 locale chunks
Peak memory, excalidraw, no cache / cached317 / 152 MB624 MBWithout the 61 locale chunks
Peak memory, three.js x10, no cache / cached422 / 244 MB695 MBLast of the three invocations
three.js x10 output7.88 MB (+2.2%), same exports7.71 MB
esbuild's own bundler tests (oracle)832 of 872 compared cases pass (95.4%)referenceCommit 07d2cdd
How we measured
Measured
Wall time of whole processes with hyperfine (cargo xtask bench --repos), median; peak RSS of one extra run (--memory). Rebuilds: examples/build_loop.rs --edit against bench/js/esbuild-rebuild.mjs, editing excalidraw-app/components/AppWelcomeScreen.tsx
Machine
Apple M-series MacBook (macOS arm64, 16 cores, 48 GB), shared with other jobs while measuring; release build, 4 threads
Software
ts-r-build release build with 4 threads; esbuild 0.28.2 pinned in bench/package.json. The three.js x10 rows were measured again on 2026-10-21 at commit 2fb2555 (load average 11-14); excalidraw rows are from commit 9c3a371
Input
excalidraw (bench/dev/excalidraw/main.tsx, .woff2 as files, .scss empty) and three.js x10 at the commits pinned in bench/repos.toml
Command
cargo xtask bench --fetch-repos --repos excalidraw,three-x10 && cargo xtask bench --repos excalidraw,three-x10 --memory
Recorded in
commit 9c3a371

Correctness

Compared with the tool ts-r-build replaces, on its own tests and on real code.

  • Bundler95.4%

    832 of 872 compared cases pass (95.4%); 198 skipped

    esbuild 0.28.2's end-to-end bundler tests. Commit 07d2cdd.

Command line

An excerpt of ts-r-build --help. You can also run it through the launcher as ts-r build.

Next to esbuild and Vite

Use ts-r-build where you call the esbuild command line today, or to build a library while the app keeps Vite. It has no JavaScript API yet, so scripts that call esbuild.build() from Node switch to the command line first. ts-r-dev uses the same bundler to pre-bundle an app’s dependencies.

ts-r-build --help
Usage: ts-r-build [options] [entry points]

  --bundle          Bundle all dependencies into the output files
  --format=...      Output format (iife | cjs | esm)
  --minify          Minify the output
  --outdir=...      The output directory
  --platform=...    Platform target (browser | node | neutral)
  --sourcemap       Emit a source map
  --splitting       Enable code splitting (requires --format=esm)
  --watch           Rebuild when a source file changes