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

196 lines 9.2 kB
import { BaseToolHandler } from '../base-handler.js'; /** * Handler for Next.js font analysis tool */ export class NextJSFontHandler extends BaseToolHandler { nextjsEngine; constructor(nextjsEngine) { super(); this.nextjsEngine = nextjsEngine; } tools = [ { name: 'nextjs_font_analysis', description: 'Analyze font loading including next/font usage, loading strategies, CLS impact, and optimization opportunities.', 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_font_analysis': return this.analyzeFonts(args, session); default: throw new Error(`Unknown Next.js font tool: ${toolName}`); } } async analyzeFonts(args, session) { try { const fontAnalysis = await this.nextjsEngine.getFontLoadingAnalysis(); let content = '🔤 **Next.js Font Analysis**\n\n'; // Check if any fonts are being used if (fontAnalysis.fontsUsingNextFont === 0 && fontAnalysis.fontsNotOptimized.length === 0 && fontAnalysis.variableFonts.length === 0) { content += '❌ **No custom fonts detected**\n\n'; content += 'Using system fonts is great for performance!\n'; content += 'If you need custom fonts, use `next/font` for optimization.\n\n'; content += '### Example with next/font:\n'; content += '```typescript\n'; content += 'import { Inter } from "next/font/google"\n\n'; content += 'const inter = Inter({ subsets: ["latin"] })\n\n'; content += 'export default function Layout({ children }) {\n'; content += ' return (\n'; content += ' <html className={inter.className}>\n'; content += ' <body>{children}</body>\n'; content += ' </html>\n'; content += ' )\n'; content += '}\n'; content += '```\n'; return { content: [{ type: 'text', text: content.trim() }] }; } // Font Loading Strategy content += '### 🎯 Font Loading Strategy\n'; content += `- **Strategy:** ${fontAnalysis.strategy}\n`; content += `- **Fonts using next/font:** ${fontAnalysis.fontsUsingNextFont}\n`; if (fontAnalysis.variableFonts.length > 0) { content += `- **Variable fonts:** ${fontAnalysis.variableFonts.join(', ')}\n`; } content += '\n'; // Not optimized fonts if (fontAnalysis.fontsNotOptimized.length > 0) { content += '### ⚠️ Fonts Not Using next/font\n'; fontAnalysis.fontsNotOptimized.forEach((font) => { content += `- ${font} (not using next/font)\n`; }); content += '\n'; content += '**Migrate to next/font for:**\n'; content += '- Automatic font optimization\n'; content += '- Zero layout shift\n'; content += '- Optimal loading performance\n'; content += '- Built-in subset optimization\n\n'; } // Performance Metrics content += '### 📊 Performance Impact\n'; content += `- **CLS Impact:** ${fontAnalysis.cls.toFixed(3)}`; if (fontAnalysis.cls > 0.1) { content += ' ⚠️ (High - causes layout shift)'; } else if (fontAnalysis.cls > 0.05) { content += ' ⚠️ (Medium - some shift)'; } else { content += ' ✅ (Good - minimal shift)'; } content += '\n'; content += `- **Font Load Time:** ${fontAnalysis.loadTime}ms`; if (fontAnalysis.loadTime > 300) { content += ' ⚠️ (Slow)'; } content += '\n\n'; // Loading strategy analysis if (fontAnalysis.strategy === 'block') { content += '⚠️ **Using "block" strategy**\n'; content += 'This can cause invisible text during font load.\n'; content += 'Consider using "swap" for better UX:\n\n'; content += '```typescript\n'; content += 'const font = localFont({\n'; content += ' src: "./font.woff2",\n'; content += ' display: "swap" // Show fallback immediately\n'; content += '})\n'; content += '```\n\n'; } // Variable fonts recommendation if (fontAnalysis.variableFonts.length === 0 && fontAnalysis.fontsUsingNextFont > 0) { content += '### 💡 Consider Variable Fonts\n'; content += 'Variable fonts can reduce file size when using multiple weights:\n\n'; content += '```typescript\n'; content += '// Instead of loading multiple weights\n'; content += 'const font = Inter({\n'; content += ' subsets: ["latin"],\n'; content += ' weight: ["400", "500", "600", "700"] // Multiple files\n'; content += '})\n\n'; content += '// Use a variable font\n'; content += 'const font = Inter({\n'; content += ' subsets: ["latin"],\n'; content += ' variable: "--font-inter" // Single file\n'; content += '})\n'; content += '```\n\n'; } // CLS optimization if (fontAnalysis.cls > 0.05) { content += '### 🎯 Reduce CLS (Layout Shift)\n\n'; content += '1. **Use size-adjust in next/font:**\n'; content += '```typescript\n'; content += 'const font = localFont({\n'; content += ' src: "./font.woff2",\n'; content += ' adjustFontFallback: true // Auto-calculates size-adjust\n'; content += '})\n'; content += '```\n\n'; content += '2. **Preload critical fonts:**\n'; content += 'next/font does this automatically!\n\n'; content += '3. **Use font-display: swap:**\n'; content += 'Shows fallback text immediately\n\n'; } // Best practices content += '### 📚 Font Loading Best Practices\n\n'; content += '1. **Always use next/font** for web fonts\n'; content += '2. **Subset fonts** to reduce size\n'; content += '3. **Use variable fonts** when possible\n'; content += '4. **Implement fallback fonts** properly\n'; content += '5. **Monitor CLS** in production\n\n'; // Example optimization content += '### 💻 Optimized Font Setup\n\n'; content += '```typescript\n'; content += '// app/layout.tsx\n'; content += 'import { Inter } from "next/font/google"\n'; content += 'import localFont from "next/font/local"\n\n'; content += '// Google font with subsetting\n'; content += 'const inter = Inter({\n'; content += ' subsets: ["latin"],\n'; content += ' display: "swap",\n'; content += ' variable: "--font-inter"\n'; content += '})\n\n'; content += '// Local font with optimization\n'; content += 'const myFont = localFont({\n'; content += ' src: "./fonts/MyFont.woff2",\n'; content += ' display: "swap",\n'; content += ' preload: true,\n'; content += ' fallback: ["system-ui", "arial"]\n'; content += '})\n'; content += '```\n'; return { content: [{ type: 'text', text: content.trim() }], fontAnalysis }; } catch (error) { throw new Error(`Failed to analyze fonts: ${error instanceof Error ? error.message : String(error)}`); } } } //# sourceMappingURL=nextjs-font-handler.js.map