Did my AI-built frontend need more libraries?
I finally built one of my side projects with AI help. I spent a lot of time writing contracts, plans, backend requirements, tests, and rules for how everything should work. Somehow, I forgot to specify the frontend stack.
After more iterations than I want to admit, I started testing it. It worked well and felt fast. I didn’t notice any obvious problems.
Then I looked at the frontend code.
The AI had used Vite, React, and MUI. But it had also written its own router, with path and parameter matching, pushState, browser back and forward handling, and screen selection. It had built a small translation engine too. Most of the code was JavaScript, and 86 files sat directly under src.
I asked it to migrate to TypeScript and feature folders. For routing, I wanted React Router. For API calls, TanStack Query with Connect-Query, since the project uses Protobuf. I also asked for React Hook Form and i18next with react-i18next.
Then I asked for a comparison.
The first migration was noticeably heavier on paper. After loading forms and language catalogs on demand, these were the final numbers:
| Metric | Original | Final |
|---|---|---|
| Frontend files | 95 | 114 |
Files under src | 86 | 104 |
| Production JS/TS lines | 9,230 | 10,117 |
| CSS lines | 1,751 | 1,751 |
| Test and fixture lines | 2,610 | 3,237 |
| Translation lines | 2,561 | 2,004 |
| Passing frontend tests | 104 | 112 |
| Direct runtime dependencies | 12 | 19 |
| Direct development dependencies | 1 | 9 |
| Initial English JS/CSS, gzip | 289.1 kB | 292.5 kB |
| Initial English JS/CSS, Brotli | 246.2 kB | 250.6 kB |
| Initial Polish JS/CSS, gzip | 289.1 kB | 311.4 kB |
| All JS/CSS chunks combined, gzip | 425.3 kB | 502.5 kB |
These numbers cover the whole migration, including TypeScript and the folder changes, so I can’t put every difference down to the libraries.
Line counts include blank lines and TypeScript declarations. Production lines exclude tests, CSS, translations, and data. Translation formatting changed, but all languages were kept.
The download figures are compression estimates from production builds. They exclude HTML, images, and API responses. A first visit only downloads some of those chunks.
The original had fewer dependencies, fewer production lines, and a smaller download. As a user, I couldn’t tell the difference. Both versions did what I needed.
I haven’t run a controlled benchmark for load times or interaction speed, so I can’t honestly say which version is faster. Both could still have bugs.
I still lean toward established libraries. They’ve been used and maintained across many projects, including situations I might never think to test. Reusing them might also cost fewer AI tokens, though I didn’t measure that.
But the custom version made me pause. The AI had written a smaller solution for this particular project. It only had to handle what I needed, while a general-purpose library has to support all sorts of options.
I’ve usually felt comfortable reaching for a library when one already exists. Now I’m wondering how much of it my project needs, and how much testing and maintenance I’d be taking on by keeping the smaller custom version.
I don’t have a firm answer yet. I still prefer the libraries, but I couldn’t point to a better experience when I used the app.