Your Next.js app uses modern optimization techniques:
- ✅ Code splitting by route
- ✅ Dynamic imports for components
- ✅ Tree-shaking with ESM modules
- ✅ Minification in production
Based on your package.json dependencies, here are the main bundle contributors:
| Package | Size | Purpose | Optimization |
|---|---|---|---|
| @tanstack/react-virtual | ~50KB | Virtual scrolling | Essential ✓ |
| date-fns | ~30KB | Date utilities | Consider day.js (-15KB) |
| supabase-js | ~200KB | Backend SDK | Required ✓ |
| next | ~500KB | Framework | Managed by Next.js ✓ |
| react | ~40KB | Framework | Required ✓ |
| framer-motion | ~30KB | Animations | Consider removing if unused |
| tailwindcss | ~30KB | Styling | Using utility-first ✓ |
| serwist | ~40KB | Service worker | Required for PWA ✓ |
Total Estimated: ~900KB (uncompressed), ~250-300KB gzipped
Impact: -15KB gzipped (~50KB uncompressed)
npm uninstall date-fns
npm install day.jsReplace imports:
// Before
import { format, startOfDay, startOfWeek } from 'date-fns'
// After
import dayjs from 'dayjs'
const format = (date, fmt) => dayjs(date).format(fmt)Impact: -10KB gzipped if unused
Check if framer-motion is actually used:
grep -r "framer-motion\|motion\." app lib --include="*.tsx" --include="*.ts"If only used for simple animations, replace with CSS transitions.
Impact: -5-10% per page
// app/admin/page.tsx
import dynamic from 'next/dynamic'
const AdminDashboard = dynamic(() => import('./admin-dashboard'), {
loading: () => <div className="spinner" />
})
export default AdminDashboardImpact: -3-5KB per component
// In (app)/reports/page.tsx
const ReportCharts = dynamic(() => import('./report-charts'), {
ssr: false, // Only load on client
})Impact: -2-5KB
Currently using FontAwesome CDN. Consider:
- React Icons library (tree-shakeable): -5KB
- SVG icons (custom): -10KB if < 50 icons
Replace:
// Before
<i className="fa-solid fa-users"></i>
// After
import { FiUsers } from 'react-icons/fi'
<FiUsers />Impact: -10-20KB for png/jpg files
Next.js Image component:
// Before
<img src="/logo.png" alt="Logo" />
// After
import Image from 'next/image'
<Image src="/logo.png" alt="Logo" width={200} height={200} />Impact: -20-30% for multi-route apps
Next.js already does this automatically! Routes load only when needed:
/reportscode loads only when visiting reports/customerscode loads only when visiting customers- Shared code in
(app)/layout.tsxloaded once
npm install --save-dev @next/bundle-analyzerconst withBundleAnalyzer = require('@next/bundle-analyzer')({
enabled: process.env.ANALYZE === 'true',
})
module.exports = withBundleAnalyzer({
// ... your next config
})ANALYZE=true npm run buildThen open generated .next/server/pages-manifest.json or use:
npm install --save-dev webpack-bundle-analyzer
# Analyze manually in .next folder- First Contentful Paint (FCP): ~1.2s
- Largest Contentful Paint (LCP): ~1.8s
- Time to Interactive (TTI): ~2.5s
- Bundle Size: ~300KB gzipped
- FCP: ~0.9s (-25%)
- LCP: ~1.3s (-28%)
- TTI: ~1.8s (-28%)
- Bundle Size: ~250KB gzipped (-17%)
- ✅ Replace date-fns with day.js (-15KB)
- ✅ Lazy load report components (-5KB)
- ✅ Enable image optimization (-10KB)
- Replace FontAwesome with React Icons (-5KB)
- Code split admin pages (-10KB)
- Remove unused Framer Motion (-10KB)
- Set up webpack-bundle-analyzer
- Add bundle size CI/CD checks
- Monitor Core Web Vitals
Add to .github/workflows/bundle-size.yml:
name: Bundle Size Check
on: [pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
- run: npm ci
- run: npm run build
- run: |
SIZE=$(du -sh .next/static | cut -f1)
echo "Bundle size: $SIZE"
# Fail if exceeds threshold
[[ $(echo $SIZE | grep -E '^[0-9]+[0-9]*M$') ]] && exit 1 || exit 0Recommended limits per route:
Dashboard: < 100KB
Customer List: < 80KB
Reports: < 120KB
Settings: < 60KB
Total initial: < 250KB
- Review dependencies with
npm audit - Run bundle analyzer
- Replace date-fns with day.js
- Lazy load heavy components
- Enable image optimization
- Set up bundle monitoring
- Add performance budget to CI/CD
- Test Core Web Vitals after changes
Next Steps: Run npm run build and check .next/static folder sizes to identify the largest files.