Let me be real: if you're still using create-react-app for production apps in 2024, you're fighting your own tooling.
At ProofMatcher, we run a marketplace for premium website templates — think animated, interactive modern web templates with live previews. Our stack? React 19, Vite, Tailwind, and Django REST Framework.
Here's why we ditched CRA and what we learned shipping this to production.
The Problem: CRA Can't Keep Up
When you're building a template marketplace, you're basically shipping a gallery of mini-apps. Each template has:
- Live previews (often with Three.js or GSAP)
- Custom animations
- Heavy asset loading
- SEO requirements
CRA's dev server started choking around 20+ templates. Cold starts took 30+ seconds. HMR felt random. Our team was spending more time waiting than coding.
Why Vite Won
Vite's dev server uses ESM natively. No more bundling everything upfront. Your browser fetches modules as needed.
The difference is night and day:
- Cold starts: ~1s vs 30s
- HMR updates: Instant vs "is it working?"
- Memory usage: ~500MB vs 2GB+
Here's our base config:
// vite.config.js
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
export default defineConfig({
plugins: [react()],
server: {
proxy: {
'/api': 'http://localhost:8000'
}
},
build: {
rollupOptions: {
output: {
manualChunks: {
vendor: ['react', 'react-dom'],
three: ['three'],
ui: ['framer-motion', 'lucide-react']
}
}
}
}
})
React 19 in Production
Yes, we're running React 19. No, it's not "unstable." The React team's been releasing canary builds for ages, and the Vite plugin handles it beautifully.
The real win? React Server Components aren't mandatory. You can use the new features (like Actions) without buying into the full RSC architecture.
Our async setup with Django:
// Using React 19's use() with Suspense
async function fetchTemplate(id) {
const res = await fetch(`/api/templates/${id}/`)
return res.json()
}
function TemplatePreview({ id }) {
const template = use(fetchTemplate(id))
return (
<div>
<h1>{template.name}</h1>
<iframe src={template.previewUrl} />
</div>
)
}
// Wrap with Suspense where used
<Suspense fallback={<TemplateSkeleton />}>
<TemplatePreview id={123} />
</Suspense>
Django + Vite: The Proxy Magic
We keep frontend and backend completely separate. Django handles:
- Authentication (JWT via SimpleJWT)
- Database models
- Stripe webhooks
- File uploads (S3 presigned URLs)
Vite proxies API requests during development, so no CORS issues:
// In Django settings.py
CORS_ALLOWED_ORIGINS = [
"http://localhost:5173", # Vite dev server
"https://proofmatcher.com",
]
# And for production:
STATICFILES_DIRS = [
BASE_DIR / "frontend-dist", # Built Vite assets
]
Performance Wins That Matter
1. Chunking Strategy
We manually split Three.js from our main bundle. Users don't pay for 3D unless they view a 3D template.
2. Image Optimization
Using Vite's built-in image handling:
import templateImage from './assets/template.jpg?w=800&format=webp'
// Generates multiple sizes, webp format
3. CSS That Doesn't Block
Tailwind + Vite's JIT mode means CSS updates are instant. No more PostCSS rebuild delays.
The Iframe Preview Solution
This was our trickiest problem: how to preview templates without style collisions.
Solution: Each preview runs in a sandboxed iframe:
<!-- Template preview component -->
<div class="preview-container">
<iframe
sandbox="allow-scripts allow-same-origin"
src={`/template-previews/${templateId}/`}
/>
</div>
Vite builds these previews as separate mini-apps in /public. Zero runtime cost for the main app.
SEO Without SSR
We get this question a lot: "How do you handle SEO without Next.js?"
Honestly? Good old <meta> tags and smart URL design. Django pre-renders critical pages (homepage, categories), and React takes over after load.
Our SEOHead component:
function SEOHead({ title, description, image }) {
return (
<>
<title>{title} | ProofMatcher</title>
<meta name="description" content={description} />
<meta property="og:image" content={image} />
<link rel="canonical" href={window.location.href} />
</>
)
}
For a marketplace, Google cares more about page speed and user experience than perfect SSR. Our Lighthouse scores:
- Performance: 98
- SEO: 100
- Accessibility: 97
Would We Do It Again?
Absolutely. Our developer experience improved dramatically:
| Metric | CRA | Vite |
|---|---|---|
| Dev server start | 30s | 1.2s |
| HMR update | 2-5s | <100ms |
| Production build | 4min | 45s |
| Bundle size (homepage) | 450KB | 180KB |
The team ships features faster. Our templates load quicker. Users stay longer.
Getting Started Yourself
If you want to try this stack:
# Frontend
npx create-vite@latest myapp --template react
cd myapp
npm install
# Backend
pip install django djangorestframework django-cors-headers
django-admin startproject backend .
Check out Vite's docs and Django REST Framework. Both have fantastic communities.
Wrapping Up
CRA served its purpose. But for modern apps with complex UIs, Vite is just better. Faster dev server, smaller bundles, better DX.
We're open sourcing our base template if you want to see the exact setup. It includes:
- React 19 + Vite config
- Django API setup
- Three.js chunking
- Iframe preview system
What's your stack look like? Still on CRA or moved to something else?
Top comments (0)