performance-check
Access: /template performance-check or /t performance-check
Analyzes your MakerKit application's performance, identifying bottlenecks and providing optimization recommendations.
What It Does
The performance-check command helps you:
- Analyze bundle sizes and code splitting
- Check Core Web Vitals compliance
- Identify slow database queries
- Review caching effectiveness
- Detect memory leaks
- Analyze API response times
- Generate performance reports
Usage
bash
/template performance-check "Description"
# or
/t performance-check "Description"When prompted, specify:
- Check type (quick scan or deep analysis)
- Performance targets
- Areas of concern
- Report format
Prerequisites
- A running MakerKit application
- Basic performance baseline
- Commercial MakerKit license from MakerKit
What Gets Analyzed
1. Bundle Size Analysis
typescript
// Bundle analyzer
async function analyzeBundleSize() {
// Run Next.js bundle analyzer
await execAsync('ANALYZE=true pnpm build');
const stats = await readBuildStats();
const issues = [];
// Check total bundle size
if (stats.totalSize > 500 * 1024) { // 500KB
issues.push({
severity: 'high',
metric: 'Total Bundle Size',
current: formatBytes(stats.totalSize),
target: '< 500KB',
impact: 'Slower initial page load',
});
}
// Check largest chunks
const largeChunks = stats.chunks
.filter(chunk => chunk.size > 100 * 1024) // 100KB
.sort((a, b) => b.size - a.size);
for (const chunk of largeChunks) {
issues.push({
severity: 'medium',
metric: `Chunk: ${chunk.name}`,
current: formatBytes(chunk.size),
target: '< 100KB',
recommendation: `Consider code splitting ${chunk.name}`,
});
}
// Check for duplicate modules
const duplicates = findDuplicateModules(stats);
if (duplicates.length > 0) {
issues.push({
severity: 'medium',
metric: 'Duplicate Modules',
current: duplicates.length,
modules: duplicates,
recommendation: 'Deduplicate shared dependencies',
});
}
return issues;
}
// Tree shaking effectiveness
async function checkTreeShaking() {
const unusedExports = await findUnusedExports();
if (unusedExports.length > 0) {
return {
severity: 'low',
metric: 'Unused Exports',
count: unusedExports.length,
files: unusedExports.slice(0, 10),
recommendation: 'Remove unused exports to reduce bundle size',
};
}
return null;
}2. Core Web Vitals
typescript
// Lighthouse CI integration
async function measureCoreWebVitals() {
const urls = [
'/',
'/dashboard',
'/billing',
'/settings',
];
const results = {};
for (const url of urls) {
const { stdout } = await execAsync(
`lighthouse ${process.env.NEXT_PUBLIC_APP_URL}${url} --output=json --quiet`
);
const report = JSON.parse(stdout);
const metrics = report.audits;
results[url] = {
lcp: metrics['largest-contentful-paint'],
fid: metrics['max-potential-fid'],
cls: metrics['cumulative-layout-shift'],
fcp: metrics['first-contentful-paint'],
ttfb: metrics['server-response-time'],
tti: metrics['interactive'],
tbt: metrics['total-blocking-time'],
score: report.categories.performance.score * 100,
};
}
return analyzeCWVResults(results);
}
function analyzeCWVResults(results) {
const issues = [];
const thresholds = {
lcp: 2500, // 2.5s
fid: 100, // 100ms
cls: 0.1, // 0.1
fcp: 1800, // 1.8s
tti: 3800, // 3.8s
};
for (const [url, metrics] of Object.entries(results)) {
for (const [metric, data] of Object.entries(metrics)) {
if (thresholds[metric] && data.numericValue > thresholds[metric]) {
issues.push({
url,
metric: metric.toUpperCase(),
current: data.displayValue,
target: `< ${thresholds[metric]}`,
severity: data.score < 0.5 ? 'high' : 'medium',
});
}
}
}
return issues;
}3. Database Performance
typescript
// Query performance analysis
async function analyzeQueryPerformance() {
const client = getSupabaseServerClient({ admin: true });
// Get slow queries
const { data: slowQueries } = await client.rpc('get_slow_queries', {
threshold_ms: 100,
limit: 20,
});
const issues = [];
for (const query of slowQueries) {
issues.push({
severity: query.mean_time > 500 ? 'high' : 'medium',
query: query.query.substring(0, 100) + '...',
avgTime: `${query.mean_time}ms`,
calls: query.calls,
recommendation: await getQueryOptimization(query),
});
}
// Check for missing indexes
const { data: missingIndexes } = await client.rpc('suggest_indexes');
for (const suggestion of missingIndexes) {
issues.push({
severity: 'medium',
table: suggestion.table_name,
columns: suggestion.columns,
reason: suggestion.reason,
sql: suggestion.create_index_sql,
});
}
// Check table sizes
const { data: tableSizes } = await client.rpc('get_table_sizes');
for (const table of tableSizes) {
if (table.total_size > 1024 * 1024 * 1024) { // 1GB
issues.push({
severity: 'low',
table: table.table_name,
size: formatBytes(table.total_size),
rows: table.row_count,
recommendation: 'Consider archiving old data or partitioning',
});
}
}
return issues;
}
// N+1 query detection
async function detectNPlusOneQueries() {
// Monitor queries during test scenarios
const scenarios = [
{ name: 'Load Dashboard', fn: loadDashboard },
{ name: 'List Projects', fn: listProjects },
{ name: 'View Team Members', fn: viewTeamMembers },
];
const issues = [];
for (const scenario of scenarios) {
const queries = await monitorQueries(scenario.fn);
// Detect repeated similar queries
const patterns = groupSimilarQueries(queries);
for (const [pattern, instances] of patterns) {
if (instances.length > 5) {
issues.push({
severity: 'high',
scenario: scenario.name,
pattern,
count: instances.length,
recommendation: 'Use JOIN or batch query instead of multiple queries',
});
}
}
}
return issues;
}4. API Performance
typescript
// API endpoint analysis
async function analyzeAPIPerformance() {
const endpoints = await getAPIEndpoints();
const issues = [];
for (const endpoint of endpoints) {
// Measure response time
const times = [];
for (let i = 0; i < 10; i++) {
const start = Date.now();
await fetch(endpoint.url, endpoint.options);
times.push(Date.now() - start);
}
const avgTime = times.reduce((a, b) => a + b) / times.length;
const p95Time = times.sort((a, b) => a - b)[Math.floor(times.length * 0.95)];
if (avgTime > 200) {
issues.push({
severity: avgTime > 1000 ? 'high' : 'medium',
endpoint: endpoint.path,
avgResponseTime: `${avgTime}ms`,
p95ResponseTime: `${p95Time}ms`,
recommendation: await getAPIOptimization(endpoint),
});
}
}
return issues;
}
// Cache effectiveness
async function analyzeCaching() {
const cacheStats = await getCacheStatistics();
const issues = [];
// Check cache hit rate
if (cacheStats.hitRate < 0.8) {
issues.push({
severity: 'medium',
metric: 'Cache Hit Rate',
current: `${(cacheStats.hitRate * 100).toFixed(1)}%`,
target: '> 80%',
recommendation: 'Review cache keys and TTL settings',
});
}
// Check cache size
if (cacheStats.size > cacheStats.maxSize * 0.9) {
issues.push({
severity: 'high',
metric: 'Cache Usage',
current: formatBytes(cacheStats.size),
max: formatBytes(cacheStats.maxSize),
recommendation: 'Increase cache size or implement eviction policy',
});
}
// Check stale data
const staleEntries = await findStaleCacheEntries();
if (staleEntries.length > 0) {
issues.push({
severity: 'low',
metric: 'Stale Cache Entries',
count: staleEntries.length,
recommendation: 'Implement cache invalidation on data updates',
});
}
return issues;
}5. Memory Usage
typescript
// Memory leak detection
async function checkMemoryUsage() {
const issues = [];
// Check Node.js memory
const memUsage = process.memoryUsage();
const heapUsedMB = memUsage.heapUsed / 1024 / 1024;
if (heapUsedMB > 500) {
issues.push({
severity: 'high',
metric: 'Heap Memory Usage',
current: `${heapUsedMB.toFixed(2)}MB`,
target: '< 500MB',
details: {
rss: formatBytes(memUsage.rss),
heapTotal: formatBytes(memUsage.heapTotal),
heapUsed: formatBytes(memUsage.heapUsed),
external: formatBytes(memUsage.external),
},
});
}
// Check for memory leaks
const leaks = await detectMemoryLeaks();
if (leaks.length > 0) {
issues.push({
severity: 'critical',
metric: 'Memory Leaks Detected',
count: leaks.length,
sources: leaks,
recommendation: 'Fix memory leaks to prevent crashes',
});
}
return issues;
}
// Component re-render analysis
async function analyzeReactPerformance() {
// Use React DevTools Profiler API
const profilerData = await collectProfilerData();
const issues = [];
// Find components with excessive re-renders
const problematicComponents = profilerData.components
.filter(c => c.renderCount > 10 && c.renderTime > 16)
.sort((a, b) => b.renderTime - a.renderTime);
for (const component of problematicComponents) {
issues.push({
severity: component.renderTime > 50 ? 'high' : 'medium',
component: component.name,
renderCount: component.renderCount,
avgRenderTime: `${component.renderTime.toFixed(2)}ms`,
recommendation: 'Use React.memo() or useMemo() to prevent unnecessary re-renders',
});
}
return issues;
}6. Image Optimization
typescript
// Image performance analysis
async function analyzeImagePerformance() {
const images = await scanProjectImages();
const issues = [];
for (const image of images) {
// Check image size
if (image.size > 200 * 1024) { // 200KB
issues.push({
severity: 'medium',
file: image.path,
currentSize: formatBytes(image.size),
recommendation: 'Compress image or use next-gen format (WebP/AVIF)',
});
}
// Check if using next/image
const usesNextImage = await checkNextImageUsage(image.path);
if (!usesNextImage) {
issues.push({
severity: 'low',
file: image.path,
issue: 'Not using next/image component',
recommendation: 'Use next/image for automatic optimization',
});
}
// Check dimensions
if (image.width > 2000 || image.height > 2000) {
issues.push({
severity: 'low',
file: image.path,
dimensions: `${image.width}x${image.height}`,
recommendation: 'Resize image to appropriate dimensions',
});
}
}
return issues;
}7. Performance Report
typescript
// Generate comprehensive performance report
export async function generatePerformanceReport() {
console.log('🚀 Starting Performance Analysis...\n');
const report = {
timestamp: new Date().toISOString(),
summary: {
score: 0,
critical: 0,
high: 0,
medium: 0,
low: 0,
},
categories: {},
recommendations: [],
};
// Run all checks
const checks = [
{ name: 'Bundle Size', fn: analyzeBundleSize, weight: 0.2 },
{ name: 'Core Web Vitals', fn: measureCoreWebVitals, weight: 0.3 },
{ name: 'Database', fn: analyzeQueryPerformance, weight: 0.2 },
{ name: 'API Performance', fn: analyzeAPIPerformance, weight: 0.15 },
{ name: 'Memory Usage', fn: checkMemoryUsage, weight: 0.1 },
{ name: 'Images', fn: analyzeImagePerformance, weight: 0.05 },
];
let totalScore = 0;
for (const check of checks) {
console.log(`Analyzing ${check.name}...`);
const issues = await check.fn();
report.categories[check.name] = issues;
// Calculate score for this category
const categoryScore = calculateCategoryScore(issues);
totalScore += categoryScore * check.weight;
// Update issue counts
for (const issue of issues) {
report.summary[issue.severity]++;
}
}
report.summary.score = Math.round(totalScore);
// Generate recommendations
report.recommendations = generateRecommendations(report);
// Create visual report
const html = generatePerformanceHTML(report);
await fs.writeFile('performance-report.html', html);
// Create JSON report
await fs.writeFile('performance-report.json', JSON.stringify(report, null, 2));
console.log('\n📊 Performance Analysis Complete!');
console.log(`Overall Score: ${report.summary.score}/100`);
console.log(`Critical Issues: ${report.summary.critical}`);
console.log(`High Priority: ${report.summary.high}`);
console.log(`Medium Priority: ${report.summary.medium}`);
console.log(`Low Priority: ${report.summary.low}`);
return report;
}
function generateRecommendations(report) {
const recommendations = [];
// Priority 1: Critical issues
if (report.summary.critical > 0) {
recommendations.push({
priority: 1,
title: 'Fix Critical Performance Issues',
description: 'Address memory leaks and blocking issues immediately',
impact: 'Prevents crashes and improves stability',
});
}
// Priority 2: Core Web Vitals
const cwv = report.categories['Core Web Vitals'];
if (cwv && cwv.some(i => i.severity === 'high')) {
recommendations.push({
priority: 2,
title: 'Improve Core Web Vitals',
description: 'Optimize LCP, FID, and CLS for better user experience',
impact: 'Better SEO and user engagement',
});
}
// Priority 3: Bundle size
const bundle = report.categories['Bundle Size'];
if (bundle && bundle.some(i => i.severity === 'high')) {
recommendations.push({
priority: 3,
title: 'Reduce JavaScript Bundle Size',
description: 'Implement code splitting and tree shaking',
impact: 'Faster initial page loads',
});
}
return recommendations;
}Automated Optimizations
The command can apply some optimizations automatically:
typescript
// Auto-optimize
export async function applyPerformanceOptimizations() {
console.log('⚡ Applying automatic optimizations...\n');
// Optimize images
await optimizeImages();
// Update Next.js config
await updateNextConfig();
// Add performance monitoring
await setupPerformanceMonitoring();
// Generate optimized builds
await execAsync('pnpm build');
console.log('✅ Optimizations applied');
}License Requirement
Important: This command requires a commercial MakerKit license from https://makerkit.dev?atp=MqaGgc MakerKit is a premium SaaS starter kit and requires proper licensing for commercial use.
