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