jQuery Projelerini Modernize Ederken Performansı Korumak
jQuery'yi tek seferde kaldırmak yerine kademeli çıkarma sırası kurmanın yolu: hangi parçaları önce taşırsanız risk ve maliyet birlikte düşer.
jQuery hâlâ birçok production sitesinde çalışıyor. Üç yıl önce yazılmış bir e-ticaret sayfası, beş yıl önce devreye alınan bir form kütüphanesi, on yıl önce başlayıp küçük eklemelerle büyüyen bir kurumsal panel... Hepsinin ortak noktası: jQuery kaldırmak için gerçek bir plan yok, ama birinin bir gün "bunu temizleyelim" diyeceği de herkes biliyor.
Projeyi baştan yazmak cazip görünür. Temiz sayfa, modern araç seti, sıfır bağımlılık. Ama tam yeniden yazma çoğu durumda en uzun, en pahalı ve en riskli yoldur; çünkü her şeyi bir seferde değiştirmek hem canlı ortamda kesintisiz davranış garantisini ortadan kaldırır, hem de neyin değiştiğini takip etmeyi güçleştirir.
Kademeli modernizasyon farklı bir mantık üzerine kurulur. jQuery'nin hangi parçalarını çıkardığınız kadar ne sırayla çıkardığınız da önemlidir; sıra yanlış seçilince kısa dönemde hem jQuery hem yeni araç yan yana çalışır, yük artar ve asıl kazanç ertelenir. Doğru sıra, her adımın hemen ölçülebilir bir fayda sağladığı ve bir sonraki adımı kolaylaştırdığı bir zincir oluşturur.
jQuery'nin Paket Ağırlığı Nereden Geliyor?
jQuery 3.x, minify ve gzip sıkıştırmasıyla yaklaşık 30 KB taşır. Sıkıştırılmamış hâli 87 KB civarındadır. Bu rakam tek başına çarpıcı görünmeyebilir; ancak asıl maliyet sayıda değildir. jQuery yüklenmeden çalışamayan her plugin, her üçüncü taraf bileşen ve her satır iç kod, bu bağımlılığı render engeli (render-blocking) hâline getirir. Bir jQuery datepicker eklentisi jQuery bitmeden başlamaz; jQuery bitmeden başlamayan kod, tarayıcı "hazır" sinyali vermeden kullanıcı etkileşimini engeller.
jQuery kaldırıldığında bu zincir kırılır. Tarayıcı gereksiz bir bağımlılığı beklemeden ayrıştırmasını sürdürür. Etki milisaniye cinsindendir ve projeden projeye değişir; ama bloklamayı kaldırmak, özellikle Time to Interactive üzerinde ölçülebilir bir fark yaratır. 30 KB'lık kütüphanenin getirdiği yük kadar, ona zincirlenen her eklentinin katkısı da bu hesaba girer.
Tüm bu maliyeti bir çırpıda sıfırlamak mümkün değildir. Kademeli çıkarmada hedef, her adımda en az bir bağımlılığı kesmek ve jQuery'yi taşıyan toplam kodu küçültmektir. Ertelenen her adım bir sonrakini daha pahalı hale getirir: plugin sayısı düşmeden AJAX katmanı taşınmaz, AJAX katmanı dururken class manipülasyonu da kalır.
$(document).ready() Neden İlk Sıraya Alınır?
Değiştirmesi en kolay parça burası. İki kalıp tam olarak denk gelir:
// jQuery
$(document).ready(function() {
// başlangıç kodu
});
// Vanilla JS
document.addEventListener('DOMContentLoaded', function() {
// başlangıç kodu
});
Ya da scripti HTML'de <body> kapanış etiketinin hemen önüne taşırsanız, DOMContentLoaded dinleyicisine de gerek kalmaz; DOM o noktada zaten hazırdır. Script konumunu düzenlemek, ek satır yazmadan aynı etkiyi verir.
Bu değişiklik jQuery bağımlılığını tek başına ortadan kaldırmaz. Ama projedeki her ready wrapper'ı kaldırmanız, başka bir jQuery çağrısıyla ne kadar iç içe geçildiğini de ortaya çıkarır. Kalan bağımlılıklar yüzeye çıkar; sonraki adım için zemin hazırlanır. Birkaç düzine satırı sadece ready wrapper'dan oluşan bir kodda bu adım neredeyse ücretsiz bir temizliktir.
AJAX Çağrılarını fetch'e Taşımak
AJAX değişimi genellikle en dikkat gerektiren adımdır. $.ajax ile yazılmış kod, çalışma mantığını jQuery'ye sıkıca bağlar; kütüphane gidince bu satırlar da gitmek zorundadır.
Basit bir GET çağrısı için fark şudur:
// jQuery
$.ajax({
url: '/api/urunler',
method: 'GET',
success: function(data) { renderList(data); },
error: function() { showError(); }
});
// Vanilla JS
fetch('/api/urunler')
.then(function(res) {
if (!res.ok) throw new Error();
return res.json();
})
.then(renderList)
.catch(showError);
POST çağrıları ve özel header yapılandırmaları biraz daha satır gerektirir, ama mantık aynıdır. JSON içeriği göndermek için Content-Type: application/json başlığını elle eklemek gerekir; jQuery bunu otomatik yapıyordu. Bu fark atlanırsa API sunucusu isteği 415 hatasıyla reddeder ve sorunu bulmak zahmetli hâle gelir. Değişimi birer birer test etmek, bu tür davranış farklılıklarını yakalamak için tek güvenilir yoldur.
Yüzlerce AJAX çağrısı olan bir projede bu geçiş uzun sürer. Ama tüm AJAX kodu taşındığında, jQuery bağımlılığının artık yalnızca DOM ve animasyon tarafında olduğu görülür. Bu görünürlük, bir sonraki adımın maliyetini tahmin etmenizi sağlar.
Projenin tamamındaki AJAX çağrılarını listelemek için $.ajax, $.get ve $.post aramalarını bir kez yapmak yeterlidir. Sonuç kaç çağrının kaldığını somut olarak gösterir; büyük rakamlar karşısında erken caymak yerine küçük kümelere bölerek ilerlemeyi tercih edebilirsiniz.
Class ve DOM Manipülasyonunu Çıkarmak
Selector ve class işlemleri, jQuery kodunun büyük bölümünü oluşturur. jQuery API'si burada özellikle kısa göründüğünden, vanilla JS karşılıklarına geçmek ilk bakışta daha fazla yazma gibi hissettirır. Tarayıcı desteği bugün neredeyse tüm çağdaş ortamları kapsadığından bu fark küçüktür.
// jQuery
$('.menu').on('click', 'li', function() {
$(this).toggleClass('secili');
});
// Vanilla JS - event delegation
document.querySelector('.menu').addEventListener('click', function(e) {
var li = e.target.closest('li');
if (li) li.classList.toggle('secili');
});
Event delegation burada kritik bir noktadır. jQuery'nin $.on(selector, handler) sözdizimi dinamik eklenen öğelerde de çalışır. Vanilla JS karşılığında closest() veya matches() ile aynı davranışı kurmanız gerekir. Bu adımı atlamak, dinamik içerikte olayların sessizce çalışmamasına yol açar ve hatayı tespit etmek zorlaşır.
Çok sayıda bileşenin birbirini tetiklediği yapılarda bu event yapılarını taşımak, her bileşenin olay modelini ayrı değerlendirmeyi zorunlu kılar. Bileşen sayısı arttıkça ortaya çıkan render maliyeti, temiz event yapısının neden gerekli olduğunu da gösterir; olay modelindeki karmaşa re-render'ları tetikleyebilir.
Animasyonları JavaScript'ten CSS'e Aktarmak
Animasyon CSS'e geçer. Bu kısa kural jQuery modernizasyonunda sık atlanan ama net fayda sağlayan bir noktayı özetler; çünkü .animate(), .slideDown(), .fadeIn() gibi çağrılar main thread'i piksel piksel hesaplamalarla meşgul eder, CSS transition ve animation ise GPU hızlandırmasına geçişe izin verir.
/* CSS */
.panel {
max-height: 0;
overflow: hidden;
transition: max-height 300ms ease;
}
.panel.acik { max-height: 500px; }
/* jQuery yerine */
/* $(".panel").slideDown(300); */
/* Vanilla JS */
document.querySelector('.panel').classList.add('acik');
Bu geçiş her animasyon için işe yaramaz. max-height geçişi, yüksekliği önceden bilinmeyen içeriklerde pürüzsüz çalışmayabilir. .animate() ile piksel değerleri doğrudan hesaplanırken CSS transition önceden tanımlı değer aralıklarıyla çalışır; içerik dinamikse requestAnimationFrame ile devam etmek daha güvenlidir. Hepsini CSS'e geçirmeye uygun sayıp toplu taşımak, sahte bir hız hissi verir ve beklenmedik görsel bozukluklar yaratır.
Animasyon geçişini değerlendirirken kullanıldığı yerleri gruplamak işe yarar: saf görsel geçişler (opacity, transform) CSS'e kolayca uyum sağlar; değeri çalışma zamanında hesaplanan animasyonlar JavaScript'te kalmak zorunda olabilir. İki grup arasındaki ayrımı baştan yapmak, hangi animasyonların sıraya gireceğini belirler.
jQuery Plugin Bağımlılıkları Ne Zaman Engel Olur?
Bazı projeler jQuery'yi doğrudan değil, eklentiler üzerinden kullanır. Özel bir select bileşeni, bir tarih seçici, bir modal kutusu... Bunların tamamı jQuery'yi bağımlılık olarak bildirir. Siz jQuery'yi çıkarmaya çalışırken bu eklentiler onu geri çekmeye devam eder.
İki seçenek vardır: ya eklentiyi jQuery gerektirmeyen muadiliyle değiştirmek, ya da o eklentiyi jQuery'yle bir arada bırakıp geri kalanı temizlemek. İkinci yaklaşım tam temizliği engeller ama kısa vadede riski düşürür. Eklenti sayısı azaldıkça jQuery'yi tamamen kaldıracak alan genişler; bir eklenti kaldığında kütüphaneyi onunla birlikte değerlendirmek kolaylaşır.
Hangi eklentinin jQuery'ye ne kadar sıkı bağlandığını anlamak için package.json veya doğrudan eklenti kaynak koduna bakmak gerekir. Bağımlılığı yalnızca API çağrısı düzeyinde olan bir eklenti, wrapper ile izole edilebilir; jQuery'nin iç nesne yapısını doğrudan kullanan eklentiler ise muadil bulmadan kaldırılamaz. Bu ayrım, modernizasyon sırasının sonuna hangi işin kaldığını netleştirir.
Doğru Sıra Risk ile Maliyeti Birlikte Düşürür
Sıra önemlidir. Önce en az yan etkili değişiklikler, sonra gözlemlenebilir davranış farkı yaratmayan kısımlar, en son etkileşim ve animasyon katmanı. Bu mantıkla ilerlediğinizde her adım tamamlandığında projenin çalışmaya devam ettiğini doğrulamak kolaylaşır.
Pratik sıra şöyle kurulabilir:
$(document).ready()kaldırın; script konumunu düzenleyin.$.ajax,$.get,$.postçağrılarınıfetchile değiştirin; her birini ayrı test edin.- Basit class manipülasyonlarını
classListAPI'ye taşıyın. - Event listener'ları vanilla JS'e çevirin; delegation mantığını
closest()ile kurun. - Animasyonları CSS'e aktarın; değeri çalışma zamanında hesaplananları
requestAnimationFrameile yönetin. - Kalan eklentileri tek tek değerlendirin; muadillerini bulun veya erteleyebileceklerinizi ayrı listede tutun.
Her adım tamamlandığında jQuery'nin hâlâ kaç satırda kullanıldığını saymak mümkün hale gelir. Bu sayı azaldıkça ne zaman tamamen kaldırılabileceği de netleşir. Mevcut kodu küçültmek mi, yoksa bölümlere ayırmak mı: karar, kalan satırın hangi API'ye bağlı olduğuna bakılarak verilir.
Bundle boyutunu adım adım izlemek istiyorsanız, her taşıma turunda üretim derlemesini karşılaştırmak somut ilerlemeyi gösterir. Build çıktısını yapılandırmayla doğrulamak, bu tür kademeli azalmaları görünür kılmanın pratik yollarından biridir; chunk boyutlarındaki değişim, hangi adımın ne kadar katkı sağladığını rakamla ortaya koyar.
Kademeli modernizasyonun getirisi yalnızca bundle boyutu değildir. Kodun okunabilirliği artar, tarayıcı standartlarına daha yakın bir yapı ortaya çıkar ve ilerleyen adımlarda farklı bir araç seti ekleme kolaylaşır. Yayına çıkmadan önce kontrol listesi tutmak, bu değişikliklerin hangisinin nerede tamamlandığını takip etmenin pratik yoludur.
Her jQuery projesi aynı hızda modernize edilemez. Eklenti yükü ağırsa, test kapsamı zayıfsa veya bu değişikliğe adanmış zaman yoksa, yavaş bir tempo tutturmak tam yeniden yazmadan daha sağlıklıdır. Aceleyle yapılan taşıma yeni hatalar yaratır; yeni hatalar eski kütüphaneye geri dönme baskısı oluşturur ve yapılan işin büyük bölümü çöpe gider.
Projenin jQuery'den bağımsızlaşması bir dönüm noktası değil, süregelen bir süreçtir. Her temizlenen çağrı bir sonrakini daha net görünür hâle getirir; her kaldırılan bağımlılık, kodun geri kalanının ne yaptığını biraz daha anlaşılır kılar. Bu artımlı netlik, taşımanın fatura ettiği gerçek değerdir.