Friday, August 01, 2025

Building a Modern React Frontend for Movie Vibes: A Journey Through CSS Frameworks, AI Timeouts, and Real-World Development

How it started ...

A couple of days ago, I shared the creation of Movie Vibes, an AI-powered Spring Boot application that analyzes movie "vibes" using Spring AI and Ollama. The backend was working beautifully, but it was time to build a proper user interface. What started as a simple "add React + Tailwind" task turned into an educational journey through modern frontend development challenges, framework limitations, and the beauty of getting back to fundamentals.


How it's going ... 

The Original Plan: React + Tailwind CSS

The plan seemed straightforward:

  • ✅ React 18 + TypeScript for the frontend
  • ✅ Tailwind CSS for rapid styling
  • ✅ Modern, responsive design
  • ✅ Quick development cycle

How hard could it be? Famous last words.


The Tailwind CSS Nightmare

The Promise vs. Reality

Tailwind CSS markets itself as a "utility-first CSS framework" that accelerates development. In theory, you get: 

  • Rapid prototyping with utility classes
  • Consistent design tokens
  • Smaller CSS bundles
  • No context switching between CSS and HTML

In practice, with Create React App and Tailwind v4, we got:

  • ๐Ÿšซ Build failures due to PostCSS plugin incompatibilities
  • ๐Ÿšซ Cryptic error messages about plugin configurations
  • ๐Ÿšซ Hours of debugging CRACO configurations
  • ๐Ÿšซ Version conflicts between Tailwind v4 and CRA's PostCSS setup

The Technical Issues

The error that started it all:
Error: Loading PostCSS Plugin failed: tailwindcss directly as a PostCSS plugin has moved to @tailwindcss/postcss

We tried multiple solutions:

  1. CRACO configuration - Failed with plugin conflicts
  2. Downgrading to Tailwind v3 - Still had PostCSS issues
  3. Custom PostCSS config - Broke Create React App's build process
  4. Ejecting CRA - Nuclear option, but defeats the purpose

The Breaking Point

After spending more time debugging Tailwind than actually building features, I made a decision: dump Tailwind entirely. Sometimes the best solution is the simplest one.

The Pure CSS Renaissance

Going Back to Fundamentals

Instead of fighting with framework abstractions, we built a custom CSS design system that:

  • Compiles instantly - No build step complications
  • Full control - Every pixel exactly where we want it
  • No dependencies - Zero external CSS frameworks
  • Better performance - Only the CSS we actually use
  • Maintainable - Clear, semantic class names

The CSS Architecture


          /* Semantic, maintainable class names */
          .movie-card {
            background: white;
            border-radius: 12px;
            box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
            transition: box-shadow 0.3s ease;
          }

          .movie-card:hover {
          	box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1);
          }

          /* Responsive design without utility class bloat */
          @media (max-width: 768px) 
          {
            .movie-card {
              /* Mobile-specific styles */
            }
          }
          

Compare this to Tailwind's approach:


<!-- Tailwind: Utility class soup -->
<div className="bg-white rounded-xl shadow-lg p-6 hover:shadow-2xl 
            	transition-shadow duration-300 md:p-8 lg:p-10">
        
Our approach is more readable, maintainable, and debuggable.

The AI Timeout Challenge

The Problem

Once the UI was working, we discovered a new issue: AI operations take time. Our local Ollama model could take 30-60 seconds to analyze a movie and generate recommendations. The frontend was timing out before the AI finished processing.

The Solution

We implemented a comprehensive timeout strategy:

// 2-minute timeout for AI operations
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 120000);

// User-friendly loading messages
<p className="loading-text">
  Please wait, this process can take 30-60 seconds while our AI agent 
  analyzes the movie and generates recommendations ✨
</p>
Key improvements:
  • ⏱️ Extended timeout to 2 minutes for AI operations
  • ๐ŸŽฏ Clear user expectations with realistic time estimates
  • ๐Ÿ”„ Graceful error handling with timeout-specific messages
  • ๐Ÿ“ฑ Loading states that don't feel broken

The Poster Image Quest

Backend Enhancement

The original backend only returned movie titles in recommendations. Users expect to see poster images! We enhanced the system to:

  1. Fetch complete metadata for the main movie ✅
  2. Parse AI-generated recommendations to extract movie titles
  3. Query OMDb API for each recommendation's metadata
  4. Include poster URLs in the API response

Performance Optimization

To balance richness with performance:

  • ๐ŸŽฏ Limit to 5 recommendations to avoid excessive API calls
  • ๐Ÿ›ก️ Fallback handling when movie metadata isn't found
  • ๐Ÿ“Š Detailed logging for debugging and monitoring

The Final Architecture

Frontend Stack

  • React 18 + TypeScript - Modern, type-safe development
  • Pure CSS - Custom utility system, no framework dependencies
  • Responsive Design - Mobile-first approach
  • Error Boundaries - Graceful handling of failures

Backend Enhancements

  • Spring Boot 3.x - Robust, production-ready API
  • Spring AI + Ollama - Local LLM for movie analysis
  • OMDb API Integration - Rich movie metadata
  • Intelligent Caching - Future enhancement opportunity

API Evolution


          {
            "movie": {
              "title": "Mission: Impossible",
              "poster": "https://...",
              "year": "1996",
              "imdbRating": "7.2",
              "plot": "Full plot description..."
            },
            "vibeAnalysis": "An exhilarating action-adventure...",
            "recommendations": [
              {
                "title": "The Bourne Identity",
                "poster": "https://...",
                "year": "2002",
                "imdbRating": "7.9"
              }
            ]
          }
         

Lessons Learned

1. Framework Complexity vs. Value

Tailwind's Promise: Rapid development with utility classes
Reality:
Build system complexity that outweighs benefits

Sometimes vanilla CSS is the better choice. Modern CSS is incredibly powerful:

  • CSS Grid and Flexbox for layouts
  • CSS Custom Properties for theming
  • CSS Container Queries for responsive design
  • CSS-in-JS when you need dynamic styles

2. AI UX Considerations

Building AI-powered applications requires different UX patterns:

  • Longer wait times are normal and expected
  • ๐Ÿ“ข Clear communication about processing time
  • ๐Ÿ”„ Progressive disclosure of results
  • ๐Ÿ›ก️ Robust error handling for AI failures

3. API Design Evolution

Starting simple and evolving based on frontend needs:

  • ๐ŸŽฏ Backend-driven initially (simple JSON responses)
  • ๐ŸŽจ Frontend-driven enhancement (rich metadata)
  • ๐Ÿ”„ Backward compatibility during transitions

4. The Beauty of Fundamentals

Modern development often pushes us toward complex abstractions, but sometimes the simplest solution is the best:

  • Pure CSS over CSS frameworks
  • Semantic HTML over div soup
  • Progressive enhancement over JavaScript-heavy approaches

Performance Results

After our optimizations:

  • ๐Ÿš€ Build time: 3 seconds (was 45+ seconds with Tailwind debugging)
  • ๐Ÿ“ฆ Bundle size: 15% smaller without Tailwind dependencies
  • Development experience: Hot reload works consistently
  • ๐ŸŽฏ User experience: Clear loading states, beautiful poster images

What's Next?

The Movie Vibes application is now production-ready with:

  • ✅ Beautiful, responsive UI
  • ✅ AI-powered movie analysis
  • ✅ Rich movie metadata with posters
  • ✅ Robust error handling
  • ✅ 2-minute AI operation support

Future enhancements could include:

  • ๐Ÿ—„️ Caching layer for popular movies
  • ๐Ÿ‘ฅ User accounts and favorites
  • ๐ŸŒ™ Dark mode theme
  • ๐Ÿณ Docker deployment setup
  • ๐Ÿงช Comprehensive testing suite

Conclusion: Embrace Simplicity

This journey reinforced a fundamental principle: complexity should solve real problems, not create them.

Tailwind CSS promised to accelerate our development but instead became a roadblock. Pure CSS, with its directness and simplicity, delivered exactly what we needed without the framework overhead.

Building AI-powered applications comes with unique challenges - long processing times, complex data transformations, and user experience considerations that traditional web apps don't face. Focus on solving these real problems rather than fighting your tools.

Sometimes the best framework is no framework at all.
Try Movie Vibes yourself:
  • Backend: mvn spring-boot:run
  • Frontend: npm start
  • Search for your favorite movie and discover its vibe! ๐ŸŽฌ✨

What's your experience with CSS frameworks? Have you found cases where vanilla CSS outperformed framework solutions? Share your thoughts in the comments!

Tech Stack:

  • Spring Boot 3.x + Spring AI
  • React 18 + TypeScript
  • Pure CSS (Custom Design System)
  • Ollama (Local LLM)
  • OMDb API

 

GitHub: tyrell/movievibes