Overnight Modernization - How Claude Code Transformed My 3-Year-Old React App
I revisited Kappa, my undergraduate thesis project from 2022 - a cluster-based comic recommender system built with React. You can check out the live application and view the source code on GitHub. What started as "let me update a few dependencies" turned into a full modernization overnight.
The starting point
When I opened the Kappa codebase, this is what I was looking at:
- Create React App with CRACO configuration
- JavaScript throughout (no TypeScript)
- React 17 with the old
ReactDOM.renderAPI - React Router v5 with outdated routing patterns
- react-instantsearch-dom (deprecated package)
- npm with a 21,000+ line package-lock.json
- Environment variables prefixed with
REACT_APP_
Functional, but very 2022.
Why bother modernizing?
Honest answer: I've been stuck on Catspense lately. Between work and life, I haven't had the deep focus sessions I need for designing a plugin system and monorepo architecture.
But I still wanted to code. Kappa was a good candidate - a "done" project with a clear modernization path. Sometimes it's better to work on something with a visible finish line than to keep grinding on something open-ended.
I was also curious whether AI could actually handle modernizing a real codebase, not just toy examples.
Using Claude Code
I'd used Claude Code at work but hadn't tested it on a full refactoring job. So I ran the experiment.
The useful thing was that it didn't just scatter updates randomly. It approached it methodically: one migration at a time, with attention to breaking changes. That's the part that actually saved time.
Phase 1: Build Tool Revolution (CRA to Vite)
The first migration was CRA to Vite. Not just swapping a build tool - it's a different build philosophy.
Why Vite over staying with CRA?
Development speed. CRA's webpack dev server was taking 15+ seconds to start and 45+ seconds for production builds. That's a slow feedback loop.
Ecosystem direction. CRA feels abandoned. React 18 support was slow, and the tooling world has moved toward Vite/ESBuild for good reasons.
Bundle optimization. Vite uses native ES modules in development and Rollup in production. Fast dev experience, optimized output.
Future-proofing. The React team stopped recommending CRA. Vite is the clear successor for React applications.
What Claude Code did:
- Removed CRACO and CRA dependencies
- Set up Vite configuration with React plugin
- Updated React 17 to 18 with the new
createRootAPI - Migrated React Router v5 to v6 with modern routing syntax
- Updated react-instantsearch-dom to react-instantsearch v7
- Switched from npm to pnpm
- Changed environment variables from
REACT_APP_toVITE_prefix
The diff: 22,677 lines deleted vs 4,950 lines added.
Phase 2: TypeScript Migration
Next was JavaScript to TypeScript. This is usually where developers spend weeks fighting type errors. Claude Code handled it in one pass.
Why TypeScript for a "finished" project?
Maintainability. I knew I'd want to add features eventually. TypeScript makes future changes safer.
Developer experience. Auto-completion, inline docs, refactoring support. Hard to go back to vanilla JavaScript once you're used to it.
Error prevention. The comic recommendation logic has complex data transformations. TypeScript catches type mismatches that would otherwise be runtime errors.
API integration. The project uses the Jikan API for manga data. TypeScript interfaces make API responses self-documenting and catch data structure changes.
What happened:
- All
.jsfiles converted to.ts/.tsx - Comprehensive
tsconfig.jsonwith strict type checking - Type definitions created in
src/types/ - Proper interfaces for React components and props
- All API responses and state management typed
- 100% compatibility with existing functionality maintained
No runtime errors after the migration. Everything worked.
Phase 3: UI Modernization with shadcn/ui
I decided to push further and modernize the UI components with shadcn/ui.
Why shadcn/ui?
Ownership. Unlike libraries that add dependencies, shadcn/ui copies components into your codebase. Full control, no external dependency risk.
Tailwind integration. Already using Tailwind, and shadcn/ui is built for it. Natural fit.
Modern design. Proper focus states, accessibility, consistent spacing. Better than my 2022 custom CSS.
Customizable. Components live in the codebase, so I can modify them without fighting a library's opinions.
No bloat. No JavaScript bundle overhead from unused components. You only ship what you use.
The changes:
- Replaced FontAwesome icons with Lucide React
- Migrated to modern Card, Button, and Badge components
- Integrated shadcn/ui with the existing kappa color scheme
- Improved hover states and transitions
The UI went from functional to modern while keeping the original design language.
Phase 4: Comic Details Page
This was the real test. I asked Claude Code to create a new Comic Details page using TanStack Query for data fetching. The comics in Kappa originally came from scraping MyAnimeList, so the same identifiers were available.
I didn't specify which API to use. I just asked for a details page with comprehensive manga info. Claude Code found and implemented the Jikan API on its own, which made sense given the MyAnimeList connection.
How it came together
API discovery. When I mentioned the comic IDs matched MyAnimeList (since the data was originally scraped from there), it identified that the Jikan API would work for fetching detailed manga information.
Data correlation. It understood the existing identifiers could be used directly with Jikan's endpoints.
Clean implementation. TanStack Query was set up with proper hooks and error handling.
Why TanStack Query was the right choice
TanStack Query fit this use case well:
Caching. The details page fetches external API data. TanStack Query caches responses and serves them instantly on repeat visits.
Loading states. isLoading, isError, isSuccess out of the box. No manual state management for loading.
Background refetching. Data stays fresh without user action. Useful for a recommendation system where manga data might update.
Error handling. Automatic retry logic. More robust than basic try-catch blocks.
Cleaner code. The useQuery hook is more declarative than useEffect-based data fetching.
What was added:
- Comic Details Page: Full manga information display with responsive design
- TanStack Query Integration: Data fetching and caching
- Hover Overlay System: Interactive card components with "View Details" buttons
- Custom Hooks:
useMangaDetailsfor Jikan API integration - TypeScript Interfaces: Type definitions for manga data
The commits
The git history tells the story:
feat: migrate from Create React App to Vitefeat: migrate to TypeScript with comprehensive type safetyfeat: modernize UI with shadcn/ui integrationfeat: implement comic details page with hover overlay and TanStack Query
Each commit was one focused migration. No mixed concerns.
What I took away from this
A few practical observations:
Time compression. What would have taken me 2-3 weeks happened in one night. That's real.
Nothing broke. At no point did the application stop working. Backwards compatibility was maintained throughout.
Learning density. I picked up more about modern React patterns, TypeScript practices, and build tool configuration in one night than I would have in weeks of doing it manually.
Good for side projects. When you're stuck on one complex project (like Catspense), using AI to make real progress on another project keeps things moving.
The results
Concrete improvements:
- Dev server: Noticeably faster startup with Vite vs the old CRA setup
- Type safety: Comprehensive TypeScript with no runtime errors
- Dependencies: Entire dependency tree modernized
- New features: Comic details page with modern data fetching patterns
- Bundle optimization: Vite's built-in optimizations
What's next
- Back to Catspense - this actually got me unstuck. Making concrete progress on one project helped with motivation for the other.
- Revisiting other old projects - I have several 2021-2022 projects that could get the same treatment.
- Building new features on Kappa - now that the foundation is modern, adding functionality is straightforward.
Closing thoughts
Three years ago I built Kappa for my thesis with the best practices I knew at the time. Last night I brought it into 2025. The final codebase looks like it was written recently - clean TypeScript, modern Vite config, contemporary React patterns, proper UI components.
The part that surprised me most wasn't the speed. It was that the quality held up. Looking at the output, it's code I'd actually want to maintain.
If you have old projects sitting around, they might be worth revisiting with AI assistance. Not everything needs to stay frozen in the year it was written.
Post #3 in my development journey. Kappa went from a 2022 thesis project to a modern 2025 React application in one night.