import React, { lazy, Suspense, useState, useEffect } from 'react';
// 1. Component lazy loading
const HeavyComponent = lazy(() => import('./HeavyComponent'));
const AdminPanel = lazy(() => import('./AdminPanel'));
const Dashboard = lazy(() => import('./Dashboard'));
function App() {
return (
<Suspense fallback={<div>Loading...</div>}>
<HeavyComponent />
</Suspense>
);
}
// 2. Route-based code splitting
import { BrowserRouter, Routes, Route } from 'react-router-dom';
const Home = lazy(() => import('./pages/Home'));
const About = lazy(() => import('./pages/About'));
const Contact = lazy(() => import('./pages/Contact'));
function AppRouter() {
return (
<BrowserRouter>
<Suspense fallback={<LoadingSpinner />}>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/contact" element={<Contact />} />
</Routes>
</Suspense>
</BrowserRouter>
);
}
// 3. Conditional component loading
function ConditionalLoad() {
const [showChart, setShowChart] = useState(false);
const [ChartComponent, setChartComponent] = useState(null);
const loadChart = async () => {
const module = await import('./Chart');
setChartComponent(() => module.default);
setShowChart(true);
};
return (
<div>
{!showChart && (
<button onClick={loadChart}>Load Chart</button>
)}
{showChart && ChartComponent && (
<Suspense fallback={<div>Loading chart...</div>}>
<ChartComponent />
</Suspense>
)}
</div>
);
}
// 4. Image lazy loading
function ImageGallery({ images }) {
return (
<div>
{images.map((img, index) => (
<img
key={index}
src={img.src}
alt={img.alt}
loading="lazy"
width={img.width}
height={img.height}
/>
))}
</div>
);
}
// 5. Custom lazy loading with Intersection Observer
function LazyImage({ src, alt, placeholder }) {
const [imageSrc, setImageSrc] = useState(placeholder);
const [imageRef, setImageRef] = useState();
useEffect(() => {
if (!imageRef) return;
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
setImageSrc(src);
observer.unobserve(entry.target);
}
});
},
{
rootMargin: '50px', // Load 50px before entering viewport
}
);
observer.observe(imageRef);
return () => {
if (imageRef) {
observer.unobserve(imageRef);
}
};
}, [imageRef, src]);
return (
<img
ref={setImageRef}
src={imageSrc}
alt={alt}
style={{ transition: 'opacity 0.3s' }}
/>
);
}
// 6. Prefetching for better UX
function PrefetchExample() {
const prefetchComponent = () => {
const component = import('./HeavyComponent');
// Component is now cached
};
return (
<button
onMouseEnter={prefetchComponent}
onClick={() => setShowComponent(true)}
>
Hover to prefetch, click to show
</button>
);
}
// 7. Dynamic imports with error handling
async function loadModuleWithRetry(importFn, retries = 3) {
try {
return await importFn();
} catch (error) {
if (retries === 0) throw error;
console.log(`Retrying import... (${retries} attempts left)`);
await new Promise(resolve => setTimeout(resolve, 1000));
return loadModuleWithRetry(importFn, retries - 1);
}
}
// Usage
const LazyComponentWithRetry = lazy(() =>
loadModuleWithRetry(() => import('./UnreliableComponent'))
);
// 8. Component-level memoization
const ExpensiveComponent = React.memo(({ data }) => {
console.log('ExpensiveComponent rendered');
// Heavy computation
const result = expensiveCalculation(data);
return <div>{result}</div>;
}, (prevProps, nextProps) => {
// Custom comparison
return prevProps.data.id === nextProps.data.id;
});
// 9. Virtual scrolling for long lists
import { FixedSizeList } from 'react-window';
function VirtualList({ items }) {
const Row = ({ index, style }) => (
<div style={style}>
{items[index].name}
</div>
);
return (
<FixedSizeList
height={600}
itemCount={items.length}
itemSize={50}
width="100%"
>
{Row}
</FixedSizeList>
);
}
// webpack.config.js optimization settings
module.exports = {
mode: 'production',
// Code splitting
optimization: {
splitChunks: {
chunks: 'all',
cacheGroups: {
// Separate vendor bundle
vendors: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
priority: 10,
},
// Separate common code
common: {
minChunks: 2,
priority: 5,
reuseExistingChunk: true,
},
// Separate React/React-DOM
react: {
test: /[\\/]node_modules[\\/](react|react-dom)[\\/]/,
name: 'react',
priority: 20,
},
},
},
// Runtime chunk for better caching
runtimeChunk: 'single',
// Minimize code
minimize: true,
},
// Performance budgets
performance: {
hints: 'warning',
maxEntrypointSize: 250000,
maxAssetSize: 250000,
},
// Bundle analysis
plugins: [
new BundleAnalyzerPlugin({
analyzerMode: 'static',
openAnalyzer: false,
}),
],
};
// Vite config for optimization
// vite.config.js
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
export default defineConfig({
plugins: [react()],
build: {
// Code splitting
rollupOptions: {
output: {
manualChunks: {
'react-vendor': ['react', 'react-dom'],
'router': ['react-router-dom'],
'ui': ['@mui/material'],
},
},
},
// Chunk size warnings
chunkSizeWarningLimit: 500,
},
});
// Resource hints in HTML
/*
<head>
<!-- Preload critical resources -->
<link rel="preload" href="/main.js" as="script">
<link rel="preload" href="/main.css" as="style">
<link rel="preload" href="/font.woff2" as="font" type="font/woff2" crossorigin>
<!-- Prefetch next page resources -->
<link rel="prefetch" href="/about.js">
<!-- Preconnect to external domains -->
<link rel="preconnect" href="https://api.example.com">
<link rel="dns-prefetch" href="https://cdn.example.com">
</head>
*/