— mission debrief · expedition K-1 —

Planet PWA

Master thesis examining the suitability of Blazor for Progressive Web Apps, compared against the JavaScript-based framework, Vue.js.

.NET 8backend
Blazorframework
Vue 3framework
PWAtarget

The thesis asked a focused question: what is it actually like to build a Progressive Web App in Blazor versus the JavaScript mainstream? Blazor lets you write front-end code in C# and run it in the browser via WebAssembly — but does it hold up against an established framework for the things a PWA has to do?

To answer it fairly, I built the same application twice — once in Blazor WebAssembly (.NET 8), once in Vue.js (Vue 3.4.29 + Vite) — with identical functionality and a shared backend. With the design held constant, any difference that surfaced could be attributed to the framework itself, not to how the app was designed. Vue served as the widely-adopted benchmark; Blazor was the system under evaluation.

The shared application is DartPointTracker, a darts scorekeeper. Players reduce a starting score (301 / 501) to exactly zero; the app records every throw, computes the remaining points in real time, and presents final standings — removing the mental arithmetic from the game. On top of scorekeeping it runs an Elo ranking: every player starts at 1000, and results shift the ranking up or down after each match.

  1. setup

    StartGame

    Pick a game mode (301/501), add existing players, or create new profiles — via the ChoosePlayer and CreateNewPlayer modals.

  2. play

    PlayGame

    Per-throw score entry (ChoosePoint), live remaining scores, turn management, and a GameSummary with final standings.

  3. rank

    PlayerRanking

    The Elo leaderboard — current standings, updated from completed games sent back to the server.

  4. pwa

    Installable & offline

    A Web App Manifest makes it installable to the home screen; a service worker handles offline scorekeeping and asset caching, with background sync for results.

Both front-ends sit on one identical backbone: a web server with a REST API over HTTPS and a database for player and Elo data. The two clients are component-based and structurally mirror each other (App → MainLayout → NavMenu → views), so the comparison stays honest.

  1. client A

    Blazor WebAssembly

    C# in the browser via WebAssembly, scaffolded with dotnet new blazorwasm --pwa — manifest and service worker pre-configured out of the box.

  2. client B

    Vue 3 + Vite

    The benchmark client, with PWA support added manually through vite-plugin-pwa (service worker, caching strategy, and manifest configured in vite.config.js).

  3. shared

    API + database

    One backend behind both: processes game results, manages players, and computes Elo. The single source of truth that keeps both clients comparable.

20–30%less code in Blazor — C# conciseness, built-in DI, convention-based routing
10 MB vs 530 KBcached app size: Blazor ships ~6.7 MB of .NET runtime; Vue tree-shakes to ~0.5 MB
40×faster HTTP in Vue — Blazor's fetch crosses the WASM↔JS boundary
30–38×faster UI diffing in Vue (virtual DOM in JS) vs Blazor crossing the boundary to apply updates

The verdict. Blazor fully meets every PWA requirement — installability, offline support, background sync — and produces a noticeably smaller, more maintainable codebase. The cost is weight and speed: a multi-megabyte runtime and the constant tax of crossing the WebAssembly–JavaScript boundary for DOM updates and network calls. Interestingly, for pure computation at scale (sorting 5,000 players) WebAssembly pulled ahead of JavaScript.

Conclusion: Blazor WebAssembly is a sound choice for PWAs where raw performance isn't the priority — especially for .NET-experienced teams and in-house tools, where development speed and long-term maintainability matter more than shaving milliseconds.