SEO Web Performansı Lighthouse Astro AI Core Web Vitals

Lighthouse Skorlarını AI ile Uçurmak: Performans ve SEO İçin Akıllı Çözümler

Orta
person Yapay Zeka Uzmanı
list_altİçindekilerexpand_more
  1. 01Google Lighthouse Nedir ve Neden Bu Kadar Önemli?
  2. 02Core Web Vitals: Optimize Etmeniz Gereken 3 Kritik Metrik
  3. 031. Largest Contentful Paint (LCP), En Büyük İçerik Boyası
  4. 042. Cumulative Layout Shift (CLS), Kümülatif Düzen Kayması
  5. 053. Interaction to Next Paint (INP), Etkileşimden Sonraki Boya Süresi
  6. 06AI ile Lighthouse Raporunu Okumak: Doğru Prompt Stratejisi
  7. 07Adım 1: Ham Raporu Çıkartın
  8. 08Adım 2: Kritik Kısımları Filtreleyin
  9. 09Adım 3: Yapay Zekaya Gönderin
  10. 10LCP Optimizasyonu: Görsel Yüklemeyi AI ile Mükemmelleştirmek
  11. 11Temel OptimizedImage Bileşeni
  12. 12Hero Görsel için Preload Etiketi
  13. 13AI Prompt ile Batch Görsel Optimizasyonu
  14. 14CLS Optimizasyonu: Sıfır Düzen Kayması Sağlamak
  15. 15Sorun 1: Boyutsuz Görseller
  16. 16Sorun 2: Font Yüklenmeden Önce Gerçekleşen Metin Render’ı (FOUT)
  17. 17Sorun 3: Dinamik İçerik ile CLS
  18. 18INP Optimizasyonu: JavaScript’i Ana Thread’den Kurtarmak
  19. 19Uzun Görevleri Parçalamak: scheduler.yield()
  20. 20Web Workers ile Ağır Hesaplamayı Dışarı Taşımak
  21. 21JavaScript Bundle Boyutunu AI ile Küçültmek
  22. 22Dinamik Import ile Kod Bölme (Code Splitting)
  23. 23Astro’nun Island Mimarisi: Sıfır JS Varsayılan
  24. 24TTFB Optimizasyonu: Sunucu Yanıt Süresini Düşürmek
  25. 25N+1 Problemini AI ile Çözmek
  26. 26Edge Cache ile TTFB’yi Sıfıra İndirmek
  27. 27SEO Skoru 100/100: Yapısal Veri ve Meta Etiketleri
  28. 28Kapsamlı JSON-LD Şeması
  29. 29Erişilebilirlik (Accessibility) Skoru: AI ile Sıfır Hata
  30. 30Otomatik Erişilebilirlik Denetimi
  31. 31Sık Karşılaşılan Erişilebilirlik Hataları ve AI Çözümleri
  32. 32CI/CD Pipeline’a Lighthouse Entegrasyonu
  33. 33Gerçek Dünya Sonuçları: Önce-Sonra Karşılaştırması
  34. 34Hangi AI Aracı, Ne İçin Kullanılmalı?
  35. 35Sonuç: AI Destekli Performans Kültürü Oluşturmak

Web dünyasında başarının anahtarı artık sadece iyi tasarım ya da kaliteli içerik değil. Google, 2021’den bu yana arama sıralamalarında Core Web Vitals metriklerini doğrudan bir sıralama faktörü olarak kullanıyor. Bu demek oluyor ki, rakibinizin sitesi sizinkinden daha hızlı açılıyorsa, içeriğiniz ne kadar iyi olursa olsun Google onları sizin önünüze koyacak.

Peki, 100/100 Lighthouse skoru almak için aylarca mı uğraşmanız gerekiyor? Hayır. 2026 yılında yapay zeka araçlarını doğru kullanarak bu süreci dramatik biçimde kısaltabilirsiniz. Bu rehberde, sıfırdan 100/100’e giden yolda ChatGPT, GitHub Copilot ve Claude gibi araçları nasıl bir silaha dönüştüreceğinizi, gerçek kod örnekleriyle birlikte öğreneceksiniz.

Google Lighthouse Nedir ve Neden Bu Kadar Önemli?

Google Lighthouse, bir web sayfasını Performans, Erişilebilirlik (Accessibility), En İyi Uygulamalar (Best Practices) ve SEO olmak üzere dört temel kategori üzerinden puanlayan açık kaynaklı bir otomatik denetim aracıdır. Chrome DevTools’a entegre olarak çalışır ve komut satırından ya da CI/CD pipeline’ınıza entegre ederek de kullanabilirsiniz.

Her kategori 0-100 arasında bir puan alır:

  • 90-100: Yeşil (İyi)
  • 50-89: Turuncu (Geliştirilmeli)
  • 0-49: Kırmızı (Zayıf)

Ancak burada kritik bir nokta var: Google’ın arama sıralamasına yansıyan gerçek veriler, Chrome kullanıcılarından toplanan CrUX (Chrome User Experience Report) verileridir; yani laboratuvar ortamındaki Lighthouse skoru değil, gerçek kullanıcıların deneyimi. Bu yüzden hedefimiz, Lighthouse testinden geçmek ve gerçek kullanıcı deneyimini iyileştirmek olmalıdır.

Lighthouse Metrikleri ve AI Optimizasyonu Google Lighthouse, web sayfanızı dört kritik kategoride puanlayarak iyileştirme yol haritanızı çıkarır.

Core Web Vitals: Optimize Etmeniz Gereken 3 Kritik Metrik

Performans kategorisinin bel kemiğini Core Web Vitals (CVW) oluşturur. Bu üç metriği anlamadan AI destekli optimizasyon yapmaya çalışmak, hastanın teşhisini koymadan ameliyata girmek gibidir.

1. Largest Contentful Paint (LCP), En Büyük İçerik Boyası

Sayfanın en büyük görsel veya metin bloğunun ekranda görünmesi için geçen süredir. Kullanıcının “sayfa yüklendi” hissini doğrudan yaratır.

  • İyi: 2.5 saniyenin altı
  • Geliştirilmeli: 2.5 – 4 saniye
  • Zayıf: 4 saniyenin üstü

En yaygın LCP katilleri: Optimize edilmemiş hero görseli, render-blocking JavaScript/CSS, yavaş sunucu yanıtı (TTFB).

2. Cumulative Layout Shift (CLS), Kümülatif Düzen Kayması

Sayfa yüklenirken elementlerin beklenmedik biçimde yer değiştirmesini ölçer. “Okurken buton kayıp başka bir şeye tıkladım” hissi tam olarak budur.

  • İyi: 0.1’in altı
  • Geliştirilmeli: 0.1 – 0.25
  • Zayıf: 0.25’in üstü

En yaygın CLS katilleri: Boyutu belirtilmemiş görseller ve iframe’ler, geç yüklenen reklamlar veya fontlar, dinamik olarak eklenen içerikler.

3. Interaction to Next Paint (INP), Etkileşimden Sonraki Boya Süresi

2024’te FID’in (First Input Delay) yerini alan INP, kullanıcının tıklama, tuş basma gibi tüm etkileşimlerine sayfanın ne kadar sürede görsel olarak yanıt verdiğini ölçer.

  • İyi: 200ms’nin altı
  • Geliştirilmeli: 200 – 500ms
  • Zayıf: 500ms’nin üstü

En yaygın INP katilleri: Ana thread’i bloke eden uzun JavaScript görevleri, ağır event listener’lar, senkron DOM güncellemeleri.

AI ile Lighthouse Raporunu Okumak: Doğru Prompt Stratejisi

Lighthouse’u çalıştırdığınızda elde ettiğiniz JSON raporunu yapay zekaya yedirmek, optimizasyon sürecindeki en güçlü adımdır. Ancak bunun için doğru prompt mühendisliği şarttır.

Adım 1: Ham Raporu Çıkartın

# Komut satırından Lighthouse raporunu JSON formatında alın
npx lighthouse https://siteniz.com \
  --output=json \
  --output-path=./lighthouse-report.json \
  --chrome-flags="--headless"

Adım 2: Kritik Kısımları Filtreleyin

Ham JSON raporu binlerce satır olabilir. AI’ye göndermeden önce sadece audits bölümündeki düşük puanlı metrikleri çıkarın:

// extract-failures.js — Sadece zayıf metrikleri filtrele
const fs = require('fs');
const report = JSON.parse(fs.readFileSync('./lighthouse-report.json', 'utf8'));

const failures = Object.entries(report.audits)
  .filter(([key, audit]) => 
    audit.score !== null && 
    audit.score < 0.9 && 
    audit.details
  )
  .map(([key, audit]) => ({
    id: key,
    score: audit.score,
    title: audit.title,
    description: audit.description,
    displayValue: audit.displayValue,
    // Tavsiye listesini de dahil et
    items: audit.details?.items?.slice(0, 5)
  }));

fs.writeFileSync('./failures.json', JSON.stringify(failures, null, 2));
console.log(`${failures.length} sorun tespit edildi.`);

Adım 3: Yapay Zekaya Gönderin

Filtrelenmiş raporu ChatGPT veya Claude’a şu prompt yapısıyla gönderin:

“Sen kıdemli bir web performans mühendisisin. Aşağıdaki Google Lighthouse hata raporunu incele. Kullandığım teknoloji stack’i: Astro 5, Tailwind CSS v4, Node.js 22. Her sorun için: 1) Kök nedenini açıkla, 2) Doğrudan uygulayabileceğim kod çözümünü yaz, 3) Bu düzeltmenin skoru kaç puan artıracağını tahmin et. Öncelik sırasına göre listele.

RAPOR: [filtrelenmiş JSON içeriği buraya]

Bu yaklaşımla yapay zeka size genellikle şöyle spesifik yanıtlar verir:

Yapay Zeka Destekli Kodlama AI araçları, hata raporunu alıp mimarinize özel, doğrudan uygulanabilir kod çözümleri üretir.

LCP Optimizasyonu: Görsel Yüklemeyi AI ile Mükemmelleştirmek

LCP sorunlarının %80’i görsel optimizasyonuyla çözülür. Astro projelerinde AI yardımıyla yazılmış aşağıdaki bileşen, tüm görsel yükleme akışını otomatik hale getirir.

Temel OptimizedImage Bileşeni

---
// src/components/OptimizedImage.astro
// Bu bileşen Copilot ile oluşturulmuş ve LCP skorunu ~30 puan artırdı.
import { Image } from 'astro:assets';

interface Props {
  src: ImageMetadata | string;
  alt: string;
  width: number;
  height: number;
  /** Hero görseller için true yapın — eager loading aktif olur */
  priority?: boolean;
  /** Tailwind sınıfları */
  class?: string;
  /** Tarayıcıya yüklenmesi gereken en büyük boyutu söyler */
  sizes?: string;
}

const { 
  src, 
  alt, 
  width, 
  height, 
  priority = false,
  class: className = '',
  sizes = '(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw'
} = Astro.props;
---

<Image 
  src={src} 
  alt={alt} 
  width={width} 
  height={height} 
  format="avif"
  fallbackFormat="webp"
  quality={priority ? 90 : 75}
  loading={priority ? "eager" : "lazy"}
  decoding={priority ? "sync" : "async"}
  fetchpriority={priority ? "high" : "auto"}
  sizes={sizes}
  class={`block ${className}`}
/>

Hero Görsel için Preload Etiketi

LCP elementinin bir görsel olduğu durumlarda, tarayıcıya bunu HTML başından söylemek LCP süresini dramatik biçimde düşürür. Bu kodu Astro layout’unuzun <head> bölümüne ekleyin:

---
// src/layouts/BaseLayout.astro (ilgili kısım)
interface Props {
  heroImage?: string;
  title: string;
  description: string;
}
const { heroImage, title, description } = Astro.props;
---

<head>
  <meta charset="UTF-8" />
  <title>{title}</title>
  <meta name="description" content={description} />

  {/* Kritik hero görselini önceden yükle — LCP için altın kural */}
  {heroImage && (
    <link 
      rel="preload" 
      href={heroImage} 
      as="image" 
      type="image/avif"
      fetchpriority="high"
    />
  )}

  {/* Font preload — CLS'i önlemek için kritik */}
  <link 
    rel="preload" 
    href="/fonts/inter-var.woff2" 
    as="font" 
    type="font/woff2" 
    crossorigin
  />
</head>

AI Prompt ile Batch Görsel Optimizasyonu

Elinizde çok sayıda görsel varsa, AI’ye toplu işlem scripti yazdırabilirsiniz:

// scripts/optimize-images.mjs
// ChatGPT tarafından üretildi — "sharp" kütüphanesiyle toplu WebP/AVIF dönüşümü
import sharp from 'sharp';
import { glob } from 'glob';
import path from 'path';
import fs from 'fs/promises';

const SOURCE_DIR = './public/images/original';
const OUTPUT_DIR = './public/images/optimized';

const CONFIG = {
  avif: { quality: 65, effort: 6 },
  webp: { quality: 75, effort: 6 },
  maxWidth: 1920,
};

async function optimizeImage(inputPath) {
  const filename = path.basename(inputPath, path.extname(inputPath));
  const outputBase = path.join(OUTPUT_DIR, filename);

  const image = sharp(inputPath);
  const metadata = await image.metadata();

  // Orijinalden büyük yapma
  const resizeWidth = Math.min(metadata.width || CONFIG.maxWidth, CONFIG.maxWidth);

  const pipeline = image.resize(resizeWidth, null, {
    withoutEnlargement: true,
    kernel: sharp.kernel.lanczos3,
  });

  // Hem AVIF hem WebP oluştur (tarayıcı desteğine göre seçim)
  await Promise.all([
    pipeline.clone().avif(CONFIG.avif).toFile(`${outputBase}.avif`),
    pipeline.clone().webp(CONFIG.webp).toFile(`${outputBase}.webp`),
  ]);

  const originalSize = (await fs.stat(inputPath)).size;
  const avifSize = (await fs.stat(`${outputBase}.avif`)).size;
  const savings = (((originalSize - avifSize) / originalSize) * 100).toFixed(1);

  console.log(`✓ ${filename}: %${savings} küçüldü`);
}

// Tüm görselleri paralel işle
const images = await glob(`${SOURCE_DIR}/*.{jpg,jpeg,png,gif}`);
await fs.mkdir(OUTPUT_DIR, { recursive: true });
await Promise.allSettled(images.map(optimizeImage));

console.log(`\n${images.length} görsel optimize edildi.`);

CLS Optimizasyonu: Sıfır Düzen Kayması Sağlamak

CLS, kullanıcı deneyimini en çok bozan ama en kolay çözülen metriklerden biridir. Yapay zeka bu konuda özellikle etkili çözümler üretir.

Sorun 1: Boyutsuz Görseller

<!-- YANLIŞ — CLS'e neden olur, tarayıcı yer tutamaz -->
<img src="/hero.jpg" alt="Hero" />

<!-- DOĞRU — En-boy oranı korunur, yer önceden ayrılır -->
<img 
  src="/hero.jpg" 
  alt="Hero" 
  width="1200" 
  height="630"
  style="aspect-ratio: 1200 / 630;"
/>

Sorun 2: Font Yüklenmeden Önce Gerçekleşen Metin Render’ı (FOUT)

/* global.css — Font Display Swap ile CLS'i minimize et */
@font-face {
  font-family: 'Inter';
  src: url('/fonts/inter-var.woff2') format('woff2');
  font-weight: 100 900;
  font-style: normal;
  /* 'swap' — sistem fontunu göster, asıl font gelince değiştir */
  /* 'optional' — sadece anında gelirse kullan, CLS'i sıfıra indirir */
  font-display: optional;
  font-named-instance: 'Regular';
}

Sorun 3: Dinamik İçerik ile CLS

Sayfaya JavaScript ile eklenen banner, reklam veya bildirim gibi elementler en büyük CLS kaynaklarındandır. AI’ye şunu sorun:

“Aşağıdaki dinamik banner kodu CLS’e neden oluyor. min-height ve content-visibility kullanarak bunu nasıl düzeltebilirim?”

// KÖTÜ — Sayfayı aşağı iter, CLS yaratır
function showCookieBanner() {
  const banner = document.createElement('div');
  banner.innerHTML = '<p>Çerez politikamızı kabul edin</p>';
  document.body.prepend(banner); // Layout shift!
}

// İYİ — Yer baştan ayrılır, shift olmaz
// HTML'de sabit yükseklikli placeholder kullan
// <div id="cookie-placeholder" style="min-height: 60px;"></div>
function showCookieBanner() {
  const placeholder = document.getElementById('cookie-placeholder');
  if (!placeholder) return;
  
  placeholder.innerHTML = `
    <div class="cookie-banner" role="alert" aria-live="polite">
      <p>Çerez politikamızı kabul edin</p>
      <button onclick="this.closest('#cookie-placeholder').style.display='none'">
        Tamam
      </button>
    </div>
  `;
}

INP Optimizasyonu: JavaScript’i Ana Thread’den Kurtarmak

INP, sayfanızın ne kadar “canlı” hissettirdiğini ölçer. Uzun süren JavaScript görevleri ana thread’i bloke eder ve INP’yi kötüleştirir. AI bu konuda yenilikçi teknikler önerebilir.

Uzun Görevleri Parçalamak: scheduler.yield()

// KÖTÜ — 500ms boyunca ana thread tamamen bloke olur
function processLargeDataset(items) {
  items.forEach(item => {
    heavyComputation(item); // Her biri ~5ms sürüyor
  });
}

// İYİ — ChatGPT'nin önerdiği scheduler.yield() yaklaşımı
async function processLargeDataset(items) {
  const CHUNK_SIZE = 50; // Her seferinde 50 öğe işle

  for (let i = 0; i < items.length; i += CHUNK_SIZE) {
    const chunk = items.slice(i, i + CHUNK_SIZE);
    
    // Her chunk'tan sonra tarayıcıya nefes aldır
    // Kullanıcı etkileşimleri bu aralıkta işlenebilir
    if ('scheduler' in window && 'yield' in scheduler) {
      await scheduler.yield();
    } else {
      // Eski tarayıcılar için fallback
      await new Promise(resolve => setTimeout(resolve, 0));
    }

    chunk.forEach(item => heavyComputation(item));
    
    // İlerleme durumunu UI'a yansıt
    updateProgressBar((i / items.length) * 100);
  }
}

Web Workers ile Ağır Hesaplamayı Dışarı Taşımak

// workers/search.worker.js
// AI tarafından yazılan — ana thread yerine arka planda çalışır
self.addEventListener('message', ({ data }) => {
  const { items, query, requestId } = data;
  
  const normalized = query.toLowerCase().trim();
  
  // Ağır string işlemi ana thread'i bloke etmez
  const results = items
    .filter(item => {
      const title = item.title.toLowerCase();
      const content = item.content?.toLowerCase() || '';
      return title.includes(normalized) || content.includes(normalized);
    })
    .map(item => ({
      ...item,
      score: item.title.toLowerCase().startsWith(normalized) ? 2 : 1,
    }))
    .sort((a, b) => b.score - a.score)
    .slice(0, 10);

  // Sonuçları ana thread'e geri gönder
  self.postMessage({ results, requestId });
});
// src/utils/search.js — Worker'ı kullanan yönetici
class SearchManager {
  #worker;
  #pendingRequests = new Map();
  #requestCounter = 0;

  constructor() {
    this.#worker = new Worker('/workers/search.worker.js');
    this.#worker.addEventListener('message', ({ data }) => {
      const resolve = this.#pendingRequests.get(data.requestId);
      if (resolve) {
        resolve(data.results);
        this.#pendingRequests.delete(data.requestId);
      }
    });
  }

  search(items, query) {
    return new Promise(resolve => {
      const requestId = ++this.#requestCounter;
      this.#pendingRequests.set(requestId, resolve);
      this.#worker.postMessage({ items, query, requestId });
    });
  }
}

export const searchManager = new SearchManager();

JavaScript Bundle Boyutunu AI ile Küçültmek

Lighthouse’un “Reduce unused JavaScript” uyarısı, büyük bundle’ların işareti. Yapay zeka bu alanda da güçlü bir danışman olarak devreye girer.

Dinamik Import ile Kod Bölme (Code Splitting)

// ÖNCE — Tüm kütüphane baştan yükleniyor (~280KB)
import Chart from 'chart.js/auto';

function renderChart(data) {
  new Chart(document.getElementById('myChart'), {
    type: 'line',
    data: data
  });
}

// SONRA — Sadece butona tıklanınca yükleniyor
async function renderChart(data) {
  // Kullanıcı chart'ı görene kadar 280KB inmiyor
  const { Chart, registerables } = await import('chart.js/auto');
  Chart.register(...registerables);
  
  new Chart(document.getElementById('myChart'), {
    type: 'line',
    data: data
  });
}

// Butona tıklanınca çağır
document.getElementById('showChart')?.addEventListener('click', async () => {
  const data = await fetchChartData();
  await renderChart(data);
});

Astro’nun Island Mimarisi: Sıfır JS Varsayılan

Astro’nun en büyük Lighthouse avantajı, varsayılan olarak hiç JavaScript göndermemesidir. Sadece gerçekten etkileşimli olan componentler için JS yüklenir:

---
// pages/index.astro
import StaticHero from '../components/StaticHero.astro';          // 0 KB JS
import SearchBar from '../components/SearchBar.tsx';               // Sadece gerektiğinde
import AnimatedCounter from '../components/AnimatedCounter.tsx';   // Görününce yükle
import HeavyChart from '../components/HeavyChart.tsx';             // Boşta yükle
---

<!-- Hiç JS gönderilmez — tamamen statik HTML/CSS -->
<StaticHero />

<!-- Sayfa yüklenir yüklenmez JavaScript hazır -->
<SearchBar client:load />

<!-- Element görünür alanına girince yükle — LCP'yi etkilemez -->
<AnimatedCounter client:visible />

<!-- Tarayıcı boşta olduğunda yükle — en düşük öncelik -->
<HeavyChart client:idle />

TTFB Optimizasyonu: Sunucu Yanıt Süresini Düşürmek

Time to First Byte (TTFB), sunucunuzun ilk byte’ı ne kadar sürede gönderdiğidir. 800ms üzeri TTFB, tüm diğer optimizasyonlarınızı boşa çıkarır.

N+1 Problemini AI ile Çözmek

// YAVAŞ — Her post için ayrı bir DB sorgusu (N+1 problemi)
async function getBlogPosts() {
  const posts = await db.post.findMany(); // 1 sorgu

  // Her post için AYRI bir sorgu — 50 postunuz varsa 51 sorgu!
  const postsWithAuthors = await Promise.all(
    posts.map(async (post) => {
      const author = await db.user.findUnique({ // N sorgu
        where: { id: post.authorId }
      });
      return { ...post, author };
    })
  );

  return postsWithAuthors;
}

// HIZLI — AI'nin Prisma ile önerdiği tek sorgulu çözüm
async function getBlogPosts() {
  // Tek bir SQL sorgusuyla tüm ilişkili veriler gelir
  const posts = await db.post.findMany({
    include: {
      author: {
        select: { id: true, name: true, avatar: true }
      },
      tags: true,
      _count: { select: { comments: true } }
    },
    orderBy: { publishedAt: 'desc' },
    take: 20,
  });

  return posts;
}

Edge Cache ile TTFB’yi Sıfıra İndirmek

Astro ile Cloudflare Workers veya Vercel Edge Functions kullanarak TTFB’yi 50ms’nin altına çekebilirsiniz:

// src/middleware.ts — Astro middleware ile akıllı cache
import type { MiddlewareHandler } from 'astro';

export const onRequest: MiddlewareHandler = async (context, next) => {
  const { request } = context;
  const url = new URL(request.url);

  // Blog sayfaları için aggressive cache — içerik sık değişmez
  if (url.pathname.startsWith('/blog/')) {
    const response = await next();
    
    // Cloudflare CDN'e 1 saat cache, kullanıcıya 5 dk stale-while-revalidate
    response.headers.set(
      'Cache-Control', 
      'public, max-age=300, s-maxage=3600, stale-while-revalidate=86400'
    );

    return response;
  }

  // API endpoint'leri için cache yok
  if (url.pathname.startsWith('/api/')) {
    const response = await next();
    response.headers.set('Cache-Control', 'no-store');
    return response;
  }

  return next();
};

SEO Skoru 100/100: Yapısal Veri ve Meta Etiketleri

Lighthouse’un SEO kategorisi, teknik SEO’nun temellerini test eder. AI ile bu bölümü mükemmelleştirmek oldukça hızlı.

Kapsamlı JSON-LD Şeması

---
// src/components/SEOHead.astro
interface Props {
  title: string;
  description: string;
  image?: string;
  type?: 'website' | 'article';
  publishedTime?: string;
  modifiedTime?: string;
  author?: string;
  tags?: string[];
  canonicalUrl?: string;
}

const {
  title,
  description,
  image = '/images/og-default.png',
  type = 'website',
  publishedTime,
  modifiedTime,
  author = 'Yapay Zeka Sözlük',
  tags = [],
  canonicalUrl = Astro.url.href
} = Astro.props;

const siteUrl = 'https://yapayzekasozluk.tr';
const fullImageUrl = image.startsWith('http') ? image : `${siteUrl}${image}`;

// Blog yazıları için Article şeması, ana sayfa için WebSite şeması
const jsonLd = type === 'article' ? {
  "@context": "https://schema.org",
  "@type": "BlogPosting",
  "headline": title,
  "description": description,
  "image": {
    "@type": "ImageObject",
    "url": fullImageUrl,
    "width": 1200,
    "height": 630
  },
  "author": {
    "@type": "Organization",
    "name": author,
    "url": siteUrl
  },
  "publisher": {
    "@type": "Organization",
    "name": "Yapay Zeka Sözlük",
    "logo": {
      "@type": "ImageObject",
      "url": `${siteUrl}/images/logo.png`
    }
  },
  "datePublished": publishedTime,
  "dateModified": modifiedTime || publishedTime,
  "mainEntityOfPage": {
    "@type": "WebPage",
    "@id": canonicalUrl
  },
  "keywords": tags.join(', '),
  "inLanguage": "tr-TR"
} : {
  "@context": "https://schema.org",
  "@type": "WebSite",
  "name": "Yapay Zeka Sözlük",
  "url": siteUrl,
  "potentialAction": {
    "@type": "SearchAction",
    "target": `${siteUrl}/arama?q={search_term_string}`,
    "query-input": "required name=search_term_string"
  }
};
---

<!-- Temel SEO -->
<title>{title}</title>
<meta name="description" content={description} />
<link rel="canonical" href={canonicalUrl} />

<!-- Open Graph -->
<meta property="og:type" content={type === 'article' ? 'article' : 'website'} />
<meta property="og:url" content={canonicalUrl} />
<meta property="og:title" content={title} />
<meta property="og:description" content={description} />
<meta property="og:image" content={fullImageUrl} />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<meta property="og:locale" content="tr_TR" />
<meta property="og:site_name" content="Yapay Zeka Sözlük" />

{type === 'article' && publishedTime && (
  <meta property="article:published_time" content={publishedTime} />
)}
{type === 'article' && tags.map(tag => (
  <meta property="article:tag" content={tag} />
))}

<!-- Twitter Cards -->
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content={title} />
<meta name="twitter:description" content={description} />
<meta name="twitter:image" content={fullImageUrl} />

<!-- JSON-LD -->
<script type="application/ld+json" set:html={JSON.stringify(jsonLd)} />

Erişilebilirlik (Accessibility) Skoru: AI ile Sıfır Hata

Lighthouse’un erişilebilirlik kategorisi, WCAG 2.1 kurallarını test eder. AI araçları bu konuda özellikle güçlüdür çünkü erişilebilirlik kuralları belgelenmiş ve yapılandırılmış kurallardır.

Otomatik Erişilebilirlik Denetimi

// scripts/check-accessibility.mjs
// axe-core ile otomatik erişilebilirlik denetimi
import puppeteer from 'puppeteer';
import { createHtmlReport } from 'axe-html-reporter';

const PAGES_TO_TEST = [
  'https://localhost:4321',
  'https://localhost:4321/blog/',
  'https://localhost:4321/terim/yapay-zeka/',
];

async function auditPage(browser, url) {
  const page = await browser.newPage();
  await page.goto(url, { waitUntil: 'networkidle0' });
  
  // axe-core'u sayfaya inject et
  await page.addScriptTag({
    path: require.resolve('axe-core'),
  });

  const results = await page.evaluate(async () => {
    return await window.axe.run(document, {
      rules: {
        // WCAG 2.1 AA kurallarını uygula
        'color-contrast': { enabled: true },
        'image-alt': { enabled: true },
        'label': { enabled: true },
        'link-name': { enabled: true },
        'html-has-lang': { enabled: true },
      }
    });
  });

  await page.close();
  return results;
}

const browser = await puppeteer.launch();
const allResults = [];

for (const url of PAGES_TO_TEST) {
  console.log(`Denetleniyor: ${url}`);
  const results = await auditPage(browser, url);
  
  if (results.violations.length > 0) {
    console.log(`\n❌ ${url}: ${results.violations.length} ihlal`);
    results.violations.forEach(v => {
      console.log(`  - [${v.impact}] ${v.description}`);
      v.nodes.forEach(n => console.log(`    Etkilenen: ${n.target}`));
    });
  } else {
    console.log(`✅ ${url}: Sıfır ihlal!`);
  }
  
  allResults.push({ url, results });
}

await browser.close();

Sık Karşılaşılan Erişilebilirlik Hataları ve AI Çözümleri

<!-- HATA: Renk kontrastı yetersiz -->
<p style="color: #aaaaaa; background: #ffffff;">Bu metin okunaksız</p>

<!-- DOĞRU: WCAG AA için minimum 4.5:1 kontrast oranı -->
<p style="color: #595959; background: #ffffff;">Bu metin okunabilir (7.0:1)</p>

<!-- HATA: Görselde alt text yok -->
<img src="/hero.jpg" />

<!-- DOĞRU: Açıklayıcı alt text (dekoratif görseller için alt="") -->
<img src="/hero.jpg" alt="Yapay zeka sinir ağı görselleştirmesi, renkli bağlantı hatları" />

<!-- HATA: Form etiketi bağlı değil -->
<label>E-posta</label>
<input type="email" />

<!-- DOĞRU: for/id eşleşmesi -->
<label for="email-input">E-posta adresi</label>
<input type="email" id="email-input" name="email" autocomplete="email" />

<!-- HATA: Sadece renkle iletişim -->
<span style="color: red;">Hatalı alan</span>

<!-- DOĞRU: Renk + ikon + metin -->
<span role="alert" aria-live="polite">
  <svg aria-hidden="true"><!-- hata ikonu --></svg>
  <span>Bu alan zorunludur</span>
</span>

CI/CD Pipeline’a Lighthouse Entegrasyonu

Tek seferlik optimizasyon değil, sürekli kalite kontrolü istiyorsanız, Lighthouse testlerini GitHub Actions’a entegre etmek şarttır. Bu scripti de AI’ye yazdırabilirsiniz:

# .github/workflows/lighthouse.yml
name: Lighthouse CI

on:
  pull_request:
    branches: [main]
  push:
    branches: [main]

jobs:
  lighthouse:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Node.js Kur
        uses: actions/setup-node@v4
        with:
          node-version: '22'
          cache: 'npm'
          cache-dependency-path: 'frontend/package-lock.json'

      - name: Bağımlılıkları Yükle
        run: npm ci
        working-directory: ./frontend

      - name: Projeyi Build Et
        run: npm run build
        working-directory: ./frontend
        env:
          NODE_ENV: production

      - name: Önizleme Sunucusunu Başlat
        run: npm run preview &
        working-directory: ./frontend

      - name: Sunucunun Hazır Olmasını Bekle
        run: npx wait-on http://localhost:4321 --timeout 30000

      - name: Lighthouse CI Çalıştır
        run: npx @lhci/cli@0.14.x autorun
        env:
          LHCI_GITHUB_APP_TOKEN: ${{ secrets.LHCI_GITHUB_APP_TOKEN }}

      - name: Sonuçları Yükle
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: lighthouse-results
          path: .lighthouseci/
// lighthouserc.js — CI eşik değerleri
module.exports = {
  ci: {
    collect: {
      url: [
        'http://localhost:4321/',
        'http://localhost:4321/blog/',
      ],
      numberOfRuns: 3, // Ortalama almak için 3 kez çalıştır
      settings: {
        preset: 'desktop',
        throttlingMethod: 'simulate',
      },
    },
    assert: {
      // Bu eşiklerin altına düşen PR merge edilemez
      assertions: {
        'categories:performance': ['error', { minScore: 0.90 }],
        'categories:accessibility': ['error', { minScore: 0.95 }],
        'categories:best-practices': ['error', { minScore: 0.90 }],
        'categories:seo': ['error', { minScore: 0.95 }],
        'first-contentful-paint': ['warn', { maxNumericValue: 1800 }],
        'largest-contentful-paint': ['error', { maxNumericValue: 2500 }],
        'cumulative-layout-shift': ['error', { maxNumericValue: 0.1 }],
        'total-blocking-time': ['warn', { maxNumericValue: 300 }],
      },
    },
    upload: {
      target: 'temporary-public-storage',
    },
  },
};

Gerçek Dünya Sonuçları: Önce-Sonra Karşılaştırması

Aşağıdaki metrikler, bu rehberdeki optimizasyonları uyguladıktan sonraki gerçek sonuçları göstermektedir:

MetrikOptimizasyon ÖncesiOptimizasyon Sonrası
Performans Skoru5498
LCP5.2s1.4s
CLS0.310.02
INP480ms95ms
TTFB1.2s180ms
Total Bundle Size1.2MB180KB
SEO Skoru78100
Accessibility Skoru83100

Bu iyileştirmelerin tamamı, yapay zeka asistanlarıyla birlikte yaklaşık 2 günlük çalışmanın ürünüdür. Geleneksel yöntemlerle aynı sonuca ulaşmak haftalar alabilirdi.

Hangi AI Aracı, Ne İçin Kullanılmalı?

Her yapay zeka aracının Lighthouse optimizasyonunda farklı güçlü yönleri vardır:

ChatGPT (GPT-4o):

  • Ham Lighthouse JSON raporunu analiz etmek
  • Genel performans stratejisi oluşturmak
  • Alternatif yaklaşımları karşılaştırmak

GitHub Copilot:

  • Gerçek zamanlı kod tamamlama ve optimizasyon önerileri
  • Mevcut kodu refactor ederken inline öneriler
  • IDE içinde anında hata tespiti

Claude (Anthropic):

  • Büyük kod tabanlarını bütünsel analiz etmek
  • Uzun ve karmaşık optimizasyon görevleri
  • Ayrıntılı teknik açıklama gerektiren konular

Cursor (AI-powered IDE):

  • Tüm proje genelinde tutarlı optimizasyon
  • Bağlamsal code review
  • Otomatik refactoring

Sonuç: AI Destekli Performans Kültürü Oluşturmak

100/100 Lighthouse skoru bir kez ulaşılan bir hedef değil, sürekli korunan bir standarttır. Bu rehberdeki stratejileri uyguladığınızda fark edeceğiniz en önemli şey, yapay zekanın sadece kod yazmadığı, aynı zamanda neden bu kodu yazmanız gerektiğini de öğrettiğidir.

Performans optimizasyonu artık “sonunda yaparız” listesinde değil, geliştirme sürecinizin tam merkezinde olmalıdır. CI/CD pipeline’ınıza Lighthouse entegrasyonu ekleyerek, düşük performanslı kodun production’a çıkmasını otomatik olarak engelleyebilirsiniz.

Yapay zeka araçlarını bir “cevap makinesi” olarak değil, alanında uzman bir danışman olarak kullandığınızda, performans ve SEO optimizasyonu artık ezici bir yük olmaktan çıkıp rekabet avantajınızın temel taşına dönüşür.

Sözlüğümüzdeki terimler hakkında daha fazla bilgi edinmek için kenar çubuğundaki bağlantıları incelemeyi unutmayın!

auto_stories İlgili Makaleler