Benchmark
Framework Comparison: TSone × Vue × React
The same todo-list app was implemented with TSone, Vue 3, and React 19 to compare bundle size and rendering performance. The experiment scripts, the three implementations, and the full raw results live in benchmarks/framework-comparison/ and are reproducible with a single command.
Experiment Design
App Under Test
- Mounts with 1000 todo items (Task 0 ~ Task 999); each row has a checkbox, a title, and a delete button
- Footer shows the total item count and the active (incomplete) count
- All three apps produce the same DOM structure; only the implementation differs (TSone class component / Vue Composition API / React function component)
Build Setup
All three apps are built with the production configuration of Bun.build (Bun 1.4.0, target browser, esm, minify); React injects process.env.NODE_ENV=production. The Vue bundle is runtime-only (no template compiler), equivalent to a bundled app whose SFCs were pre-compiled.
Measurement Methodology
A real browser (headless Chrome) loads each app from a local static server; every framework runs 3 rounds × 5 iterations and the median is reported. Mount time is measured from an inline timestamp in the HTML head until the first render completes; update time is measured from the moment the update function is called until the last DOM mutation (tracked by a MutationObserver), with no frame-wait floor.
add1000: append 1000 items (single commit)toggle1000: toggle the first 1000 items (single commit)remove1000: remove the first 1000 items (single commit)toggleEach1000: toggle 1000 items one by one (one independent update each, to observe batching behavior)
Bundle Size
| Framework | Raw | gzip | brotli | gzip relative |
|---|---|---|---|---|
| TSone | 37.4 KB | 11.1 KB | 9.9 KB | 18.8% |
| Vue 3.5 | 94.9 KB | 36.8 KB | 32.8 KB | 62.2% |
| React 19 | 187.4 KB | 59.2 KB | 51.1 KB | 100% |
Sizes are for the entry main.js, including the framework runtime; relative size uses React gzip as 100%.
Rendering Performance (median, ms)
| Operation | TSone | Vue 3 | React 19 |
|---|---|---|---|
| Mount (1000 items) | 19.9 | 43.0 | 62.0 |
| add1000 | 16.6 | 11.5 | 10.1 |
| toggle1000 | 18.8 | 6.5 | 5.4 |
| remove1000 | 18.8 | 6.1 | 5.1 |
| toggleEach1000 (one by one × 1000) | 8.1 | 4.6 | 10.2 |
Interpretation
Bundle Size: A Clear Win for TSone
TSone is 11.1 KB after gzip — about 1/5.3 of React (59.2 KB) and 1/3.3 of Vue (36.8 KB). The 0.4 KB increase over the previous run (10.7 KB) corresponds to newly added runtime capabilities: watch, Transition, KeepAlive, error boundaries, and router guards. The smaller runtime pays off on slow networks, low-end devices, and first-load scenarios.
Mount Time: Same Order of Magnitude
Mounting 1000 items lands in the 20-62 ms range for all three frameworks, with TSone the fastest. React is relatively higher, mostly due to runtime initialization and module parsing.
Single Batch Updates: Slower but Imperceptible
One-shot bulk operations stay below 20 ms in all three frameworks. TSone is roughly 1.5-3.7× slower than Vue/React (about 1.5× for add1000, about 3× for toggle/remove) because every update rebuilds and diffs the full list of VNodes, whereas Vue/React benefit from optimized keyed rendering.
Fine-Grained Updates: Automatic Batching Closes the Gap
Updating 1000 items one by one (toggleEach1000) takes about 8.1 ms in TSone, in the same league as Vue (~4.6 ms) and React (~10.2 ms), and down from 9.7 ms in the previous run thanks to value-level props diffing and batched setProps. TSone ships a built-in automatic batching scheduler: a burst of synchronous state changes is merged into a single render on a microtask. Before this optimization the effect ran synchronously and re-rendered on every change, putting this metric at about 12 seconds; automatic batching improves it by roughly 1200×, matching Vue’s microtask scheduler and React’s automatic batching.
Note that batching is asynchronous: DOM updates land on a microtask after state changes. Use flushSync() when you need to read the latest DOM synchronously, or await nextTick() in async code.
Environment and Reproduction
| Item | Value |
|---|---|
| TSone | 0.4.0 (workspace source, with automatic batching) |
| Bun | 1.4.0 |
| Chrome | 152.0.7977.83 (headless) |
| Vue | 3.5.42 |
| React / react-dom | 19.2.8 |
| playwright-core | 1.62.1 |
| Rounds × Iterations | 3 × 5 |