#!/usr/bin/env node /** * PageSpeed Insights API Check * Prüft die Performance einer URL mit der Google PageSpeed Insights API */ import https from 'https'; // Disable SSL verification for local testing (network proxy issue) process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; const API_KEY = 'AIzaSyA4qo0LfLy_ps-SyTQTQpFrFRjDnAUn_K4'; const URL_TO_TEST = 'https://www.damjan-savic.com/'; function httpsGet(url) { return new Promise((resolve, reject) => { https.get(url, (res) => { let data = ''; res.on('data', chunk => data += chunk); res.on('end', () => { try { resolve(JSON.parse(data)); } catch (e) { reject(new Error(`JSON Parse Error: ${e.message}`)); } }); }).on('error', reject); }); } async function runPageSpeedTest(url, strategy = 'mobile') { const apiUrl = `https://www.pagespeedonline.googleapis.com/pagespeedonline/v5/runPagespeed?url=${encodeURIComponent(url)}&key=${API_KEY}&strategy=${strategy}&category=performance&category=accessibility&category=best-practices&category=seo`; console.log(`\n🔍 Analysiere ${url} (${strategy})...\n`); console.log('⏳ Bitte warten, die Analyse kann 30-60 Sekunden dauern...\n'); try { const data = await httpsGet(apiUrl); if (data.error) { throw new Error(`API Error: ${data.error.message}`); } return data; } catch (error) { console.error('❌ Fehler bei der API-Anfrage:', error.message); throw error; } } function formatScore(score) { const percentage = Math.round(score * 100); if (percentage >= 90) return `\x1b[32m${percentage}\x1b[0m`; // Grün if (percentage >= 50) return `\x1b[33m${percentage}\x1b[0m`; // Gelb return `\x1b[31m${percentage}\x1b[0m`; // Rot } function formatTime(ms) { if (ms < 1000) return `${Math.round(ms)}ms`; return `${(ms / 1000).toFixed(1)}s`; } function displayResults(data, strategy) { const lighthouse = data.lighthouseResult; const categories = lighthouse.categories; const audits = lighthouse.audits; console.log('═'.repeat(60)); console.log(`📊 PageSpeed Insights Ergebnis (${strategy.toUpperCase()})`); console.log('═'.repeat(60)); // Scores console.log('\n📈 SCORES:'); console.log('─'.repeat(40)); console.log(` Performance: ${formatScore(categories.performance.score)}`); console.log(` Barrierefreiheit: ${formatScore(categories.accessibility.score)}`); console.log(` Best Practices: ${formatScore(categories['best-practices'].score)}`); console.log(` SEO: ${formatScore(categories.seo.score)}`); // Core Web Vitals console.log('\n⚡ CORE WEB VITALS:'); console.log('─'.repeat(40)); const fcp = audits['first-contentful-paint']; const lcp = audits['largest-contentful-paint']; const tbt = audits['total-blocking-time']; const cls = audits['cumulative-layout-shift']; const si = audits['speed-index']; console.log(` First Contentful Paint (FCP): ${formatTime(fcp.numericValue)}`); console.log(` Largest Contentful Paint (LCP): ${formatTime(lcp.numericValue)}`); console.log(` Total Blocking Time (TBT): ${formatTime(tbt.numericValue)}`); console.log(` Cumulative Layout Shift (CLS): ${cls.displayValue}`); console.log(` Speed Index: ${formatTime(si.numericValue)}`); // Opportunities const opportunities = Object.values(audits) .filter(audit => audit.details?.type === 'opportunity' && audit.details?.overallSavingsMs > 0) .sort((a, b) => (b.details?.overallSavingsMs || 0) - (a.details?.overallSavingsMs || 0)) .slice(0, 5); if (opportunities.length > 0) { console.log('\n💡 OPTIMIERUNGSMÖGLICHKEITEN:'); console.log('─'.repeat(40)); opportunities.forEach(opp => { const savings = opp.details?.overallSavingsMs; console.log(` • ${opp.title}`); if (savings) { console.log(` Potenzielle Einsparung: ${formatTime(savings)}`); } }); } // Diagnostics const diagnostics = Object.values(audits) .filter(audit => audit.details?.type === 'table' && audit.score !== null && audit.score < 0.9) .slice(0, 5); if (diagnostics.length > 0) { console.log('\n🔧 DIAGNOSE:'); console.log('─'.repeat(40)); diagnostics.forEach(diag => { const scoreIcon = diag.score >= 0.5 ? '⚠️' : '❌'; console.log(` ${scoreIcon} ${diag.title}`); }); } // Passed Audits Count const passedAudits = Object.values(audits).filter(a => a.score === 1).length; const totalAudits = Object.values(audits).filter(a => a.score !== null).length; console.log('\n✅ BESTANDENE PRÜFUNGEN:'); console.log('─'.repeat(40)); console.log(` ${passedAudits} von ${totalAudits} Prüfungen bestanden`); console.log('\n' + '═'.repeat(60)); return { performance: Math.round(categories.performance.score * 100), accessibility: Math.round(categories.accessibility.score * 100), bestPractices: Math.round(categories['best-practices'].score * 100), seo: Math.round(categories.seo.score * 100), lcp: lcp.numericValue, fcp: fcp.numericValue, tbt: tbt.numericValue, cls: parseFloat(cls.displayValue) }; } async function main() { console.log('\n🚀 PageSpeed Insights API Test'); console.log('================================\n'); console.log(`URL: ${URL_TO_TEST}`); console.log(`API Key: ${API_KEY.substring(0, 10)}...`); try { // Mobile Test const mobileData = await runPageSpeedTest(URL_TO_TEST, 'mobile'); const mobileResults = displayResults(mobileData, 'mobile'); // Desktop Test console.log('\n\n'); const desktopData = await runPageSpeedTest(URL_TO_TEST, 'desktop'); const desktopResults = displayResults(desktopData, 'desktop'); // Summary console.log('\n\n📋 ZUSAMMENFASSUNG:'); console.log('═'.repeat(60)); console.log(`\n 📱 Mobile:`); console.log(` Performance: ${formatScore(mobileResults.performance / 100)}`); console.log(` LCP: ${formatTime(mobileResults.lcp)}`); console.log(` TBT: ${formatTime(mobileResults.tbt)}`); console.log(`\n 🖥️ Desktop:`); console.log(` Performance: ${formatScore(desktopResults.performance / 100)}`); console.log(` LCP: ${formatTime(desktopResults.lcp)}`); console.log(` TBT: ${formatTime(desktopResults.tbt)}`); console.log('\n' + '═'.repeat(60)); } catch (error) { console.error('\n❌ Test fehlgeschlagen:', error.message); process.exit(1); } } main();