The Task Board Experiment
One task board, built four times
Built the same task board four times with the help of Claude Code, to see how easy it is to build a certain front end framework with the help of AI. Same API, same features, four very different outcomes.
Boards are view-only. No drag-and-drop, no create/edit/delete. Just wanted to see how fast I can build the app using different frameworks and tech stack and how they would look like when you give AI the power to decide the implementation.
React
Tailwind CSS + shadcn/ui + Lucide React
Open the app →Vue
Tailwind CSS + PrimeVue + PrimeIcons
Open the app →Svelte
Tailwind CSS + Skeleton UI + Lucide Svelte
Open the app →Angular
Angular Material + Material Icons
Open the app →Release status
- Done: all four apps built and added feedback for "how easy to launch the app" & "folder structure." AI Usage noted for all four, and task boards deployed to Cloudflare Pages to see if they will have deployment issues.
- Pending: Readability ratings, and checking how easy it is to add a new feature with minimal AI help.
Findings & Comparison
Stack per app
| React | Vue | Svelte | Angular | |
|---|---|---|---|---|
| UI library | shadcn/ui | PrimeVue | Skeleton UI | Angular Material |
| Icons | Lucide React | PrimeIcons | Lucide Svelte | Material Icons |
| Data fetching | TanStack Query | TanStack Query | TanStack Query | HttpClient + RxJS + signals |
Ratings
| Metric | React | Vue | Svelte | Angular |
|---|---|---|---|---|
| How easy to launch the app | 5/5 | 5/5 | 1/5 | 5/5 |
| How readable the generated code is | pending | pending | pending | pending |
| How easy to add new features manually | pending | pending | pending | pending |
| Folder structure made sense | 4/5 | 4.5/5 | 5/5 | 3.5/5 |
| Claude Weekly usage delta | +2% | +1% | +1% | +1% |
Cross-stack findings
The API doesn't send CORS headers
The live API sends no CORS headers at all, so a browser can't call it directly cross-origin.
Confirmed via an OPTIONS preflight — a 405 response with no CORS headers
present.
Fixed the same way in every app: proxy /api through the dev server (Vite's
server.proxy for React/Vue/Svelte, proxy.conf.json for Angular), then swap
in a Cloudflare Pages Function to do the same job once it's actually deployed.
The same API returns two different response shapes
columns and categories return a bare array. users and
tasks switch to { data, pagination } once limit or
offset is passed — same API, inconsistent shape depending on endpoint and query params.
Every app's API client normalizes both shapes to a plain array.
Notable findings
PrimeVue quietly went premium
Installing PrimeVue for the Vue app surfaced a licensing change: primevue@latest
resolves to 5.0.1, whose own npm description now reads "a premium UI library"
(previously "open source") and pulls in @primeui/license-manager — described as an
"offline license verifier for PrimeUI and PrimeUI PRO" — as a hard dependency. The repo's MIT
LICENSE.md still technically covers it, but the license-manager coupling was enough
uncertainty to avoid risking it on a free portfolio piece.
Pinned PrimeVue to ^4.5.5 instead — still explicitly "open source," still dist-tagged
v4-stable — with primeicons@^8.0.0 (just a CSS icon font, unaffected
either way). Its theming package, @primevue/themes, turned out to be deprecated too, in
favor of @primeuix/themes — switched to that instead of installing something already
marked dead.
Svelte + TanStack Query v6: noticeably less stable
Svelte 5's new runes combined with a brand-new TanStack Query v6 adapter (rewritten specifically for runes) proved noticeably less stable than the React or Vue combinations. Initial dev-mode behavior showed multi-second delays before first paint, with no console or terminal errors. Repeated dev-server restarts while investigating this likely destabilized Codespaces' port-forwarding layer, surfacing a second, unrelated-looking failure: the board wouldn't load via the forwarded browser URL at all, again with nothing in the console or terminal pointing toward a cause.
A significant share of that app's build session went into debugging an issue entirely outside the code. The likely cause was correctly diagnosed, but there was no way to directly access or reset Codespaces' forwarding daemon to confirm or fix it.
The fix was removing the stale forwarded port manually in the Codespaces' Ports panel.
Angular 22 wants a newer Node than this repo has
Scaffolding Angular with the latest CLI hit an immediate wall: @angular/cli@latest is
22.1.6, requiring Node ^22.22.3 || ^24.15.0 || >=26.0.0. This repo's
devcontainer is pinned to Node 20, shared across all four apps — Angular 22 won't run in it.
Dropped to Angular ^21.2.22 instead — the newest major still compatible with Node 20
(^20.19.0 || ^22.12.0 || >=24.0.0), consistent with the same tradeoff made throughout
the session with TypeScript (6.0.2 over 7.0.2) and PrimeVue (v4 over v5): take the newest version
that doesn't conflict with what's already in place. The shared devcontainer was deliberately left
untouched rather than bumped — that's a bigger change affecting three apps already reviewed and
signed off, so that call was left to the project owner rather than made unilaterally. Not an
oversight. A tradeoff.
Deployment
Once all four apps were built, they were combined into a single deployment — one Cloudflare Pages project, all four apps and this page under their own paths.
Three clean, one déjà vu
React, Vue, and Angular deployed to Cloudflare Pages and just worked, first try — no surprises. Svelte deployed successfully too, but hit the exact same "stuck on loading columns" flakiness in production that showed up back in dev, needing a few refreshes before it'd actually load.
This is the interesting part: it happened on a completely fresh environment — no Codespaces, no dev server, no port-forwarding layer anywhere in the picture. Which means the original dev-mode slowness probably wasn't just a Codespaces problem after all — there's likely something real going on in the app or query stack itself. Best guess right now: TanStack Svelte Query v6's rune-based query initialization on first mount. Still not confirmed.
Lessons learned
Missing .gitignore in the initial brief
node_modules/ and build artifacts were committed before this was caught and cleaned up after the fact.
Lesson: spell out .gitignore requirements in the brief itself, upfront — not patch it in after the first commit.