8.3 KiB
8.3 KiB
📊 Bundle Analysis Guide
Simple guide for analyzing and optimizing bundle sizes.
🎯 Quick Analysis
Frontend Bundle Analysis
# Analyze bundle size
pnpm analyze
# Or use the script
pnpm bundle-analyze
Key Metrics to Monitor
- First Load JS: Should be < 250KB
- Total Bundle Size: Should be < 1MB
- Largest Chunks: Identify optimization targets
🎯 Frontend Optimizations
1. Bundle Analysis & Code Splitting
# Analyze current bundle size
cd apps/portal
pnpm run analyze
# Build with analysis
pnpm run build:analyze
2. Dynamic Imports
// Before: Static import
import { HeavyComponent } from './HeavyComponent';
// After: Dynamic import
const HeavyComponent = lazy(() => import('./HeavyComponent'));
// Route-level code splitting
const Dashboard = lazy(() => import('./pages/Dashboard'));
const Orders = lazy(() => import('./pages/Orders'));
3. Image Optimization
// Use Next.js Image component with optimization
import Image from 'next/image';
<Image
src="/hero.jpg"
alt="Hero"
width={800}
height={600}
priority={false} // Lazy load non-critical images
placeholder="blur" // Add blur placeholder
/>
4. Tree Shaking Optimization
// Before: Import entire library
import * as _ from 'lodash';
// After: Import specific functions
import { debounce, throttle } from 'lodash-es';
// Or use individual packages
import debounce from 'lodash.debounce';
5. React Query Optimization
// Optimize React Query cache
const queryClient = new QueryClient({
defaultOptions: {
queries: {
// Reduce memory usage
cacheTime: 5 * 60 * 1000, // 5 minutes
staleTime: 1 * 60 * 1000, // 1 minute
// Limit concurrent queries
refetchOnWindowFocus: false,
},
},
});
🎯 Backend Optimizations
1. Heap Size Optimization
// package.json - Optimized heap sizes
{
"scripts": {
"dev": "NODE_OPTIONS=\"--max-old-space-size=2048\" nest start --watch",
"build": "NODE_OPTIONS=\"--max-old-space-size=3072\" nest build",
"type-check": "NODE_OPTIONS=\"--max-old-space-size=4096\" tsc --noEmit"
}
}
2. Streaming Responses
// For large data responses
@Get('large-dataset')
async getLargeDataset(@Res() res: Response) {
const stream = this.dataService.createDataStream();
res.setHeader('Content-Type', 'application/json');
res.setHeader('Transfer-Encoding', 'chunked');
stream.pipe(res);
}
3. Memory-Efficient Pagination
// Cursor-based pagination instead of offset
interface PaginationOptions {
cursor?: string;
limit: number; // Max 100
}
async findWithCursor(options: PaginationOptions) {
return this.prisma.order.findMany({
take: Math.min(options.limit, 100),
...(options.cursor && {
cursor: { id: options.cursor },
skip: 1,
}),
orderBy: { createdAt: 'desc' },
});
}
4. Request/Response Caching
// Memory-efficient caching
@Injectable()
export class CacheService {
private readonly cache = new Map<string, { data: any; expires: number }>();
private readonly maxSize = 1000; // Limit cache size
set(key: string, data: any, ttl: number = 300000) {
// Implement LRU eviction
if (this.cache.size >= this.maxSize) {
const firstKey = this.cache.keys().next().value;
this.cache.delete(firstKey);
}
this.cache.set(key, {
data,
expires: Date.now() + ttl,
});
}
}
5. Database Connection Optimization
// Optimize Prisma connection pool
const prisma = new PrismaClient({
datasources: {
db: {
url: process.env.DATABASE_URL,
},
},
// Optimize connection pool
__internal: {
engine: {
connectionLimit: 10, // Reduce from default 20
},
},
});
🎯 Dependency Optimizations
1. Replace Heavy Dependencies
# Before: moment.js (67KB)
npm uninstall moment
# After: date-fns (13KB with tree shaking)
npm install date-fns
# Before: lodash (71KB)
npm uninstall lodash
# After: Individual functions or native alternatives
npm install lodash-es # Better tree shaking
2. Bundle Analysis Results
# Run bundle analysis
./scripts/memory-optimization.sh
# Key metrics to monitor:
# - First Load JS: < 250KB
# - Total Bundle Size: < 1MB
# - Largest Chunks: Identify optimization targets
3. Webpack Optimizations (Already Implemented)
- Code Splitting: Separate vendor, common, and UI chunks
- Tree Shaking: Remove unused code
- Compression: Gzip/Brotli compression
- Caching: Long-term caching for static assets
🎯 Runtime Optimizations
1. Memory Leak Detection
// Add memory monitoring
@Injectable()
export class MemoryMonitorService {
@Cron('*/5 * * * *') // Every 5 minutes
checkMemoryUsage() {
const usage = process.memoryUsage();
if (usage.heapUsed > 500 * 1024 * 1024) { // 500MB
this.logger.warn('High memory usage detected', {
heapUsed: `${Math.round(usage.heapUsed / 1024 / 1024)}MB`,
heapTotal: `${Math.round(usage.heapTotal / 1024 / 1024)}MB`,
external: `${Math.round(usage.external / 1024 / 1024)}MB`,
});
}
}
}
2. Garbage Collection Optimization
# Enable GC logging in production
NODE_OPTIONS="--max-old-space-size=2048 --gc-interval=100" npm start
# Monitor GC patterns
NODE_OPTIONS="--trace-gc --trace-gc-verbose" npm run dev
3. Worker Threads for CPU-Intensive Tasks
// For heavy computations
import { Worker, isMainThread, parentPort } from 'worker_threads';
if (isMainThread) {
// Main thread
const worker = new Worker(__filename);
worker.postMessage({ data: largeDataset });
worker.on('message', (result) => {
// Handle processed result
});
} else {
// Worker thread
parentPort?.on('message', ({ data }) => {
const result = processLargeDataset(data);
parentPort?.postMessage(result);
});
}
📈 Monitoring & Metrics
1. Performance Monitoring
// Add performance metrics
@Injectable()
export class PerformanceService {
trackMemoryUsage(operation: string) {
const start = process.memoryUsage();
return {
end: () => {
const end = process.memoryUsage();
const diff = {
heapUsed: end.heapUsed - start.heapUsed,
heapTotal: end.heapTotal - start.heapTotal,
};
this.logger.debug(`Memory usage for ${operation}`, diff);
},
};
}
}
2. Bundle Size Monitoring
// Add to CI/CD pipeline
{
"scripts": {
"build:check-size": "npm run build && bundlesize"
},
"bundlesize": [
{
"path": ".next/static/js/*.js",
"maxSize": "250kb"
},
{
"path": ".next/static/css/*.css",
"maxSize": "50kb"
}
]
}
🚀 Implementation Checklist
Immediate Actions (Week 1)
- Run bundle analysis:
pnpm run analyze - Implement dynamic imports for heavy components
- Optimize image loading with Next.js Image
- Reduce heap allocation in development
Short-term (Week 2-3)
- Replace heavy dependencies (moment → date-fns)
- Implement request caching
- Add memory monitoring
- Optimize database connection pool
Long-term (Month 1)
- Implement streaming for large responses
- Add worker threads for CPU-intensive tasks
- Set up continuous bundle size monitoring
- Implement advanced caching strategies
🎯 Expected Results
Memory Reduction Targets
- Frontend Bundle: 30-50% reduction
- Backend Heap: 25-40% reduction
- Build Time: 20-30% improvement
- Runtime Memory: 35-50% reduction
Performance Improvements
- First Load: < 2 seconds
- Page Transitions: < 500ms
- API Response: < 200ms (95th percentile)
- Memory Stability: No memory leaks in 24h+ runs
🔧 Tools & Commands
# Frontend analysis
cd apps/portal && pnpm run analyze
# Backend memory check
cd apps/bff && NODE_OPTIONS="--trace-gc" pnpm dev
# Full optimization analysis
./scripts/memory-optimization.sh
# Dependency audit
pnpm audit --recursive
# Bundle size check
pnpm run build && ls -la .next/static/js/
Note: Always test memory optimizations in a staging environment before deploying to production. Monitor application performance and user experience after implementing changes.