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
JavaScript
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