DEV Community

qingkuai
qingkuai

Posted on

Frontend Framework Bundle Size Benchmark: React/Vue/Angular vs Fine-Grained Runtimes

Framework discussions usually focus on DX, ecosystem, and runtime performance. But users experience something earlier than all of that: download, decompress, parse, then execute.

That is why I built this benchmark: to make framework bundle-size tradeoffs visible under the same feature scope and the same reporting rules.


What I benchmarked

I implemented the same TodoMVC feature set across multiple frameworks, then generated one unified report.

The report compares:

  • raw size
  • minified size
  • minified + gzip size

It also breaks totals down by:

  • runtime
  • template
  • script
  • style

Fairness constraints

To reduce noise from implementation differences:

  • all frameworks implement the same TodoMVC behavior
  • template/script/style outputs are extracted and compared
  • styles are scoped in all implementations (TSX-based implementations use CSS Modules)
  • the UI does not select style by default, but style is still included in stats

Why style is not selected by default in the chart controls:

style usually has limited optimization room in this setup, and differences are often tiny and mostly caused by framework-added scoping metadata rather than major architecture differences.


Mainstream group: React, Angular, Vue (Vue 3)

At 1 component (minified):

  • Angular: ~201.69 KB
  • React: ~189.44 KB
  • Vue 3: ~65.64 KB

The key reason is runtime cost. In the same report view:

  • Angular runtime: ~195.39 KB
  • React runtime: ~185.66 KB
  • Vue 3 runtime: ~61.83 KB

As component count grows, the gap expands. Angular rises fastest, React also stays high, and Vue 3 remains lower overall in this group in this benchmark.


Fine-grained group: Solid, Vue Vapor, Svelte 5, QingKuai

The ecosystem trend is clear: less generic virtual-DOM diffing, more dependency-precise updates (fine-grained reactivity).

But in practice, frameworks in the same direction can still differ a lot.

At 1 component (minified):

  • Solid: ~19.04 KB
  • QingKuai: ~25.42 KB
  • Svelte 5: ~39.25 KB
  • Vue Vapor: ~47.27 KB

If you only look at the starting point, Solid is smallest in this group.

But if you look at growth curves, the story changes:

  • QingKuai grows more smoothly and ends up lowest at high component counts in this run
  • Solid starts smallest but grows faster
  • Svelte 5 and Vue Vapor stay above QingKuai in higher component-count ranges, while Vue Vapor remains below Solid and Svelte 5 at larger scales

So the useful takeaway is not just “fine-grained is better.”
It is: how the runtime is organized and how costs scale with component count matters more than a single low starting number.


Why Svelte 4 deserves a separate note

Svelte 4 has a very attractive small-app story.

At 1 component (minified), it is ~11.08 KB in this benchmark, with runtime at ~0.71 KB.

But at larger scales, its curve becomes much steeper than peers in this comparison.

This suggests a common risk pattern for larger apps:

  • very low centralized runtime cost
  • more repeated implementation fragments embedded in component output
  • total size grows quickly as component count increases

Practical guidance from this dataset:

  • for very small apps (for example, under ~10 components), Svelte 4 can still be a reasonable choice
  • for larger applications, evaluate growth slope early, not just the smallest demo number

The metric that matters: starting point + slope

This benchmark reinforced four points for me:

  1. Bundle size should be a first-class framework selection metric.
  2. “No virtual DOM + fine-grained” is an important direction, but implementations in that direction can still differ significantly.
  3. The smallest 1-component result is not enough.
  4. For medium/large apps, growth slope is often more important than the best single-point minimum.

Reproduce locally

git clone https://github.com/mlgq/frontend-framework-bundle-size.git
cd frontend-framework-bundle-size
pnpm install
pnpm run report
Enter fullscreen mode Exit fullscreen mode

Links

If you find an unfair implementation detail or have better optimizations, critiques and PRs are welcome.

Top comments (0)