Quick Answer
Most vibe-coded apps ship 3-5MB of JavaScript on initial load when the budget should be under 500KB. AI tools import entire libraries instead of individual functions, include unused dependencies, skip image optimization, and generate inline styles instead of utility classes. The result is an app that takes 5-8 seconds to become interactive on mobile. Fix it by auditing your bundle, removing unused imports, lazy-loading heavy components, and compressing images.
The Page Weight Problem in AI-Generated Apps
AI code generators optimize for functionality, not performance. When you ask for a chart, they import all of Chart.js. When you ask for a date picker, they import all of Moment.js. When you ask for an icon, they import the entire icon library. Each of these choices adds hundreds of kilobytes to your bundle.
Google's 2024 Core Web Vitals data shows that pages with total weight over 3MB have a 53% bounce rate on mobile, compared to 25% for pages under 1MB. The HTTP Archive's 2024 State of the Web report found that the median page weight is now 2.3MB, but AI-generated apps frequently exceed 5MB due to unoptimized dependency trees.
Every additional 100KB of JavaScript adds roughly 350ms of parse time on a mid-range mobile device. Users perceive anything over 3 seconds as slow, and Google's Core Web Vitals directly penalize pages where Largest Contentful Paint (LCP) exceeds 2.5 seconds.
Where the Weight Comes From
| Source | Typical Bloat | AI Tool Habit | Right Approach |
|---|---|---|---|
| Full library imports | 200-800KB | import _ from 'lodash' |
import get from 'lodash/get' |
| Moment.js | 330KB (with locales) | Imported for simple date formatting | Use date-fns (tree-shakeable, 2KB per function) |
| Icon libraries | 500KB+ | import * from 'react-icons' |
Import individual icons only |
| Unoptimized images | 1-5MB per image | Full-resolution PNGs in hero sections | WebP/AVIF, responsive srcset, lazy loading |
| CSS frameworks | 200-400KB | Full Bootstrap imported, 5% used | Tailwind with purge, or CSS modules |
| Unused dependencies | 100-500KB | Dependencies from abandoned features | Audit and remove with depcheck |
How to Audit Your Page Weight
Before fixing anything, measure what you are shipping. Three tools give you the full picture:
Lighthouse Performance Audit. Open Chrome DevTools, go to Lighthouse, and run a Performance audit on mobile. Look at Total Blocking Time (TBT), Largest Contentful Paint (LCP), and the "Reduce unused JavaScript" opportunity. Lighthouse tells you how much JavaScript is loaded but never executed.
Bundle Analyzer. For Next.js apps, run ANALYZE=true next build with @next/bundle-analyzer. For Vite apps, use rollup-plugin-visualizer. These tools visualize every dependency in your bundle by size, making it obvious which imports are consuming the most space.
Network Tab. Chrome DevTools Network tab with "Disable cache" checked and throttling set to "Slow 3G" shows you the real user experience. Sort by size to find the largest resources.
Fixing the Most Common Issues
// ❌ BAD - Full library import (pulls in 600KB)
import _ from 'lodash';
const value = _.get(data, 'user.name');
// ✅ GOOD - Tree-shakeable import (pulls in 2KB)
import get from 'lodash/get';
const value = get(data, 'user.name');
// ❌ BAD - Moment.js for simple formatting (330KB)
import moment from 'moment';
const formatted = moment(date).format('MMM D, YYYY');
// ✅ GOOD - date-fns (2KB for format function)
import { format } from 'date-fns';
const formatted = format(date, 'MMM d, yyyy');
// ❌ BAD - Loading heavy component on initial render
import HeavyChart from './HeavyChart';
// ✅ GOOD - Lazy load components not in the viewport
import { lazy, Suspense } from 'react';
const HeavyChart = lazy(() => import('./HeavyChart'));
function Dashboard() {
return (
<Suspense fallback={<div>Loading chart...</div>}>
<HeavyChart />
</Suspense>
);
}
Setting a Page Weight Budget
A performance budget prevents regressions after you fix the initial bloat. Set hard limits that block deployment if exceeded:
| Resource Type | Budget (Compressed) | Why This Limit |
|---|---|---|
| Total JavaScript | < 300KB | Under 1s parse time on mid-range mobile |
| Total CSS | < 50KB | Render-blocking, affects FCP |
| Total Images (above fold) | < 200KB | Affects LCP directly |
| Total Page Weight | < 1MB | Under 3s load on 3G |
| Third-party Scripts | < 100KB | Analytics, chat widgets, ad scripts |
Tools like VibeDoctor (vibedoctor.io) automatically measure your page weight, detect full-library imports, and flag heavy bundle issues in your deployed site and codebase. Free to sign up.
FAQ
What is a good page weight for a web app?
Under 1MB compressed total for the initial load. JavaScript should be under 300KB compressed. For landing pages that need to rank well, aim for under 500KB total. The lighter the page, the better your Core Web Vitals scores and the lower your bounce rate.
Does tree shaking fix the problem automatically?
Only partially. Tree shaking removes unused exports from ES modules, but many libraries (Moment.js, Lodash default import, icon packs) are not tree-shakeable because they use CommonJS or export everything from a single entry point. You need to use tree-shakeable alternatives or import from specific subpaths.
How much does page weight affect SEO?
Google uses Core Web Vitals (LCP, CLS, INP) as ranking signals. Page weight directly affects LCP - heavier pages take longer to render the largest content element. Pages that fail Core Web Vitals thresholds are ranked lower than faster competitors with similar content quality.
Should I use a CDN to fix page weight issues?
A CDN reduces latency (download time) but does not reduce page weight (total bytes). If you are shipping 5MB of JavaScript, a CDN makes it download faster but the browser still has to parse and execute all 5MB. Fix the weight first, then add a CDN for latency. Both matter, but weight is the bigger problem.