UNPKG

ai-debug-local-mcp

Version:

🎯 ENHANCED AI GUIDANCE v4.1.2: Dramatically improved tool descriptions help AI users choose the right tools instead of 'close enough' options. Ultra-fast keyboard automation (10x speed), universal recording, multi-ecosystem debugging support, and compreh

236 lines 11.4 kB
import { BaseToolHandler } from '../base-handler.js'; /** * Handler for Next.js PPR (Partial Prerendering) and HMR (Hot Module Replacement) tools */ export class NextJSPPRHMRHandler extends BaseToolHandler { nextjsEngine; constructor(nextjsEngine) { super(); this.nextjsEngine = nextjsEngine; } tools = [ { name: 'nextjs_ppr_analysis', description: 'Analyze Partial Prerendering (PPR) including static shells, dynamic holes, streaming performance, and Suspense boundaries.', inputSchema: { type: 'object', properties: { sessionId: { type: 'string', description: 'Debug session ID' } }, required: ['sessionId'] } }, { name: 'nextjs_hmr_monitor', description: 'Monitor Hot Module Replacement (HMR) and Fast Refresh including update speed, failures, and state preservation.', inputSchema: { type: 'object', properties: { sessionId: { type: 'string', description: 'Debug session ID' } }, required: ['sessionId'] } } ]; async handle(toolName, args, sessions) { const session = sessions.get(args.sessionId); if (!session) { throw new Error(`Debug session ${args.sessionId} not found`); } // Validate this is a Next.js app if (session.framework !== 'nextjs' && session.framework !== 'next' && !(session.framework === 'react' && session.isNextJS)) { throw new Error('This tool only works with Next.js applications'); } switch (toolName) { case 'nextjs_ppr_analysis': return this.analyzePPR(args, session); case 'nextjs_hmr_monitor': return this.monitorHMR(args, session); default: throw new Error(`Unknown Next.js PPR/HMR tool: ${toolName}`); } } async analyzePPR(args, session) { try { const analysis = await this.nextjsEngine.getPPRAnalysis(); let content = '🎯 **Next.js Partial Prerendering Analysis**\n\n'; // Check if PPR is enabled (if no static shells, PPR is not being used) if (!analysis || !analysis.staticShells || analysis.staticShells.length === 0) { content += '❌ **PPR is not enabled**\n\n'; content += 'Partial Prerendering is an experimental feature that combines:\n'; content += '- Static shells for instant loading\n'; content += '- Dynamic holes for personalized content\n'; content += '- Streaming for optimal performance\n\n'; content += '### How to Enable PPR\n\n'; content += '```javascript\n'; content += '// next.config.js\n'; content += 'module.exports = {\n'; content += ' experimental: {\n'; content += ' ppr: true\n'; content += ' }\n'; content += '}\n'; content += '```\n\n'; content += 'Then use in your routes:\n'; content += '```typescript\n'; content += '// app/page.tsx\n'; content += 'export const experimental_ppr = true\n'; content += '```\n'; return { content: [{ type: 'text', text: content.trim() }] }; } // PPR is enabled content += `### 📊 PPR Overview\n\n`; content += `- **Static Shells:** ${analysis.staticShells?.length || 0}\n`; content += `- **Dynamic Holes:** ${analysis.dynamicHoles?.length || 0}\n`; content += `- **Suspense Boundaries:** ${analysis.suspenseBoundaries || 0}\n\n`; // Static Shells if (analysis.staticShells && analysis.staticShells.length > 0) { content += '### 🏗️ Static Shells\n'; analysis.staticShells.forEach((shell) => { content += `- ${shell}\n`; }); content += '\n'; } // Dynamic Holes if (analysis.dynamicHoles && analysis.dynamicHoles.length > 0) { content += '### 🕳️ Dynamic Holes\n'; analysis.dynamicHoles.forEach((hole) => { content += `- **${hole.component}**\n`; content += ` Reason: ${hole.reason}\n`; content += ` Size: ${hole.size} bytes\n\n`; }); } // Streaming Performance if (analysis.streamingPerformance) { content += '### 🌊 Streaming Performance\n\n'; content += `- **TTFB:** ${analysis.streamingPerformance.ttfb}ms\n`; content += `- **Chunks:** ${analysis.streamingPerformance.chunks}\n`; content += `- **Total Time:** ${analysis.streamingPerformance.totalTime}ms\n\n`; } // Performance Impact content += '### 🚀 Performance Impact\n\n'; content += 'PPR combines the best of SSG and SSR:\n'; content += '- **Instant loading** with static shells\n'; content += '- **Fresh data** with streaming updates\n'; content += '- **Better Core Web Vitals** scores\n'; content += '- **Reduced server load** with caching\n\n'; // Best Practices content += '### 📚 PPR Best Practices\n\n'; content += '1. **Wrap dynamic content** in Suspense boundaries\n'; content += '2. **Keep static shells light** for fast loading\n'; content += '3. **Stream heavy components** progressively\n'; content += '4. **Use loading.tsx** for better UX\n'; content += '5. **Monitor streaming performance** in production\n'; return { content: [{ type: 'text', text: content.trim() }], analysis }; } catch (error) { throw new Error(`Failed to analyze PPR: ${error instanceof Error ? error.message : String(error)}`); } } async monitorHMR(args, session) { try { const hmrData = await this.nextjsEngine.getHMRAnalysis(); let content = '🔥 **Next.js HMR Monitor**\n\n'; // Overall stats content += `### 📊 HMR Statistics\n\n`; content += `- **Successful Updates:** ${hmrData.updates || 0}\n`; content += `- **Average Update Time:** ${Math.round(hmrData.avgUpdateTime || 0)}ms\n`; content += `- **Failed Updates:** ${hmrData.failures || 0}\n`; content += `- **State Preservation:** ${hmrData.statePreservation ? '✅ Working' : '❌ Issues detected'}\n\n`; // Performance Analysis const avgTime = hmrData.avgUpdateTime || 0; if (avgTime > 1000) { content += '### ⚠️ Performance Issues Detected\n\n'; content += '- **Slow update times** (>1s average)\n'; content += 'Consider:\n'; content += ' - Reducing component complexity\n'; content += ' - Optimizing dependencies\n'; content += ' - Checking for circular imports\n\n'; } // Recent Updates (failed ones) if (hmrData.recentUpdates && hmrData.recentUpdates.length > 0) { const failedUpdates = hmrData.recentUpdates.filter((update) => !update.success); if (failedUpdates.length > 0) { content += '### ❌ Recent HMR Failures\n\n'; failedUpdates.forEach((failure) => { content += `- **${failure.files?.join(', ') || 'Unknown file'}**\n`; content += ` Duration: ${failure.duration}ms\n`; if (failure.timestamp) { const time = new Date(failure.timestamp).toLocaleTimeString(); content += ` Time: ${time}\n`; } content += '\n'; }); content += 'Common causes:\n'; content += '- Syntax errors in code\n'; content += '- Import/export mismatches\n'; content += '- Type errors (TypeScript)\n'; content += '- Circular dependencies\n\n'; } } // State Preservation if (!hmrData.statePreservation) { content += '### ⚠️ State Preservation Issues\n\n'; content += 'Component state may be lost on updates.\n'; content += 'This might be due to:\n'; content += '- Non-function component exports\n'; content += '- Anonymous components\n'; content += '- Dynamic component creation\n\n'; content += 'Fix by using named function components:\n'; content += '```typescript\n'; content += '// ❌ Anonymous\n'; content += 'export default () => { ... }\n\n'; content += '// ✅ Named\n'; content += 'export default function MyComponent() { ... }\n'; content += '```\n\n'; } // HMR Best Practices content += '### 💡 HMR Best Practices\n\n'; content += '1. **Use named exports** for better tracking\n'; content += '2. **Keep components small** for faster updates\n'; content += '3. **Avoid side effects** in component bodies\n'; content += '4. **Use React DevTools** for state debugging\n'; content += '5. **Check console** for HMR warnings\n\n'; // Optimization Tips if (avgTime > 500) { content += '### 🚀 Optimization Tips\n\n'; content += '```javascript\n'; content += '// Split large components\n'; content += 'const Header = lazy(() => import("./Header"))\n'; content += 'const Footer = lazy(() => import("./Footer"))\n\n'; content += '// Use memo for expensive renders\n'; content += 'const ExpensiveComponent = memo(() => {\n'; content += ' // Heavy computation\n'; content += '})\n'; content += '```\n'; } return { content: [{ type: 'text', text: content.trim() }], hmrData }; } catch (error) { throw new Error(`Failed to monitor HMR: ${error instanceof Error ? error.message : String(error)}`); } } } //# sourceMappingURL=nextjs-ppr-hmr-handler.js.map