4 puan yazan GN⁺ 2024-11-04 | 1 yorum | WhatsApp'ta paylaş
  • Cash, IE11+ modern tarayıcılarda DOM’u manipüle etmek için jQuery tarzı söz dizimi sunan, çok küçük bir jQuery alternatifi kütüphanesidir
  • Modern tarayıcı özelliklerinden yararlanarak kod tabanını küçültür ve alışılmış zincirleme metotları çok daha küçük dosya boyutuyla kullanmayı sağlar
  • jQuery ile %100 işlevsel eşdeğerlik hedeflemez, ancak günlük kullanım senaryolarının çoğunu kapsar ve uyguladığı API genel olarak jQuery ile uyumludur
  • Boyutu minified & gzipped olarak 6KB’dır; jQuery Slim 3.4.1’in 24.4KB boyutuna kıyasla %76,6 daha küçüktür ve partial builds ile daha da azaltılabilir
  • TypeScript kod tabanı, koddan üretilen TypeScript tipleri, ad alanlı olaylar ve tek tek metotların hariç tutulabildiği kısmi derlemeleri destekler

Cash’in çözdüğü sorun

  • Cash, modern tarayıcılar için bir jQuery alternatifi olarak DOM manipülasyonu için jQuery tarzı $() seçicisi ve zincirlenebilir koleksiyon metotları sunar
  • Destek hedefi IE11+ tarayıcılardır
  • Amaç jQuery’nin tüm özelliklerini birebir uygulamak değildir, ancak Cash’in uyguladığı özellikler çoğunlukla jQuery API’siyle uyumlu olacak şekilde tasarlanmıştır
  • jQuery’den geçiş yapan kullanıcılar migration guide belgesini inceleyebilir

Boyut ve özellik karşılaştırması

  • Dosya boyutu karşılaştırmasında Cash, Zepto 1.2.0 ve jQuery Slim 3.4.1’den daha küçüktür
    • Unminified: 36.5KB
    • Minified: 16KB
    • Minified & Gzipped: 6KB
  • jQuery Slim 3.4.1 minified & gzipped olarak 24.4KB’dır; Cash buna kıyasla %76,6 boyut tasarrufu sağlar
  • Daha küçük bir bundle gerekiyorsa partial builds kullanılabilir
  • Özellik karşılaştırmasına göre Cash modern tarayıcı desteği, aktif bakım, ad alanlı olaylar, TypeScript kod tabanı ve koddan üretilen TypeScript tipleri sunar
  • Partial builds için Cash’te tek tek metotlar hariç tutulabilir; Zepto ve jQuery Slim’de ise tüm modüller düzeyinde hariç tutma olarak gösterilir

Kullanım

  • Cash, jsDelivr üzerinden yüklenip tarayıcıda doğrudan kullanılabilir
<script src="https://cdn.jsdelivr.net/npm/cash-dom/…;
<script>
  $(function () {
    $('html').addClass ( 'dom-loaded' );
    $('<footer>Appended with Cash</footer>').appendTo ( document.body );
  });
</script>
npm install --save cash-dom
import $ from "cash-dom";

$(function () {
  $('html').addClass ( 'dom-loaded' );
  $('<footer>Appended with Cash</footer>').appendTo ( document.body );
});

API yapısı

  • $(), Cash’in temel seçici metodudur ve manipüle edilebilir düğüm koleksiyonları döndürür
  • Bir fonksiyon geçirildiğinde DOM hazır olduğunda bu fonksiyonu çalıştırır
  • $() selector, DOM node, nodeList, HTML string, Cash collection ve document ready callback alabilir
  • Cash genel olarak üç API sunar
    • Sorgu seçicisi
    • Koleksiyon metotları
    • Global $ nesnesinin kütüphane metotları

Koleksiyon metotları

  • Koleksiyon metotları, $() ile bir koleksiyon oluşturduktan sonra $(element).addClass(className) gibi çağrılır
  • Sunulan kategoriler özellikler, koleksiyon, CSS, veri, boyutlar, efektler, olaylar, form, DOM manipülasyonu, offset ve gezinme olarak ayrılır
  • Başlıca metotlar şunları içerir
    • Sınıf/özellik: addClass, removeClass, toggleClass, attr, prop, removeAttr
    • Koleksiyon işleme: add, each, eq, filter, first, get, map, slice
    • DOM manipülasyonu: append, prepend, before, after, html, text, clone, remove, replaceWith, wrap
    • Olaylar: on, off, one, ready, trigger
    • Gezinme: find, children, closest, parent, parents, siblings, next, prev
  • Bazı extra methods sunulur, ancak varsayılan olarak devre dışıdır
  • $.fn, koleksiyonların ana prototipidir ve eklenti gibi tüm koleksiyonlara özel metotlar eklemeye olanak tanır

Global Cash metotları

  • Global $ nesnesi tip kontrolü ve yardımcı metotlar içerir
  • Tip kontrol metotları $.isArray, $.isFunction, $.isNumeric, $.isPlainObject, $.isWindow sunar
  • Yardımcılar arasında $.guid, $.each, $.extend, $.parseHTML, $.unique bulunur
  • $.extend, hedef nesneyi kaynak nesnenin özellikleriyle genişletir ve derin genişletmeyi de destekler
  • $.parseHTML, HTML string’inden bir koleksiyon döndürür; $.unique ise tekrarları kaldırılmış yeni bir dizi döndürür

Genişletme ve katkı

  • Cash özel metotlarla genişletilebilir; genişletme yöntemi extending Cash belgesinde anlatılmıştır
  • Sorunlar veya özellik istekleri GitHub’da issue olarak açılabilir
  • Pull request iş akışı sırasıyla depoyu klonlama, bağımlılıkları kurma, npm run dev ile otomatik yeniden derleme, npm run test ile testleri çalıştırma ve gerekirse README’yi güncellemedir
  • Lisans MIT’dir

1 yorum

 
GN⁺ 2024-11-04
Hacker News yorumları
  • Günümüz tarayıcıları oldukça iyi hale geldiği için DOM manipülasyonunu basitleştirmek adına çoğu zaman aşağıdaki iki satırlık alias yeterli oluyor
    dqs = document.querySelector.bind(document);
    dqsA = document.querySelectorAll.bind(document);
    Böylece document.querySelector('#country') yerine dqs('#country'), document.querySelectorAll('.city') yerine de dqsA('.city') gibi kullanılabiliyor
    Geri kalanı için sadece yerel tarayıcı fonksiyonlarını kullanmak da sorun değil; genelde de import { dqs, dqsA } from '/lib/js/dqs.js'; gibi bir modülden içe aktarılıyor
    https://github.com/no-gravity/dqs.js

    • querySelector/querySelectorAll için bağlanmış bu iki satırın kendisi kullanışlı ve makul görünüyor, ama bunu import ile almak abartı
      Sonuçta sadece iki basit satır; bağımlılık yapmaya gerek yok, kopyalayıp yapıştırmak yeterli
    • Her yardımcı fonksiyon tek satırlık değil
      Örneğin birden fazla olayı ele alan $.fn.one() veya $.fn.on() jQuery/Cash ile daha kolay kullanılıyor; iç implementasyona bakınca da epey iş olduğu görülüyor: https://github.com/fabiospampinato/cash/blob/master/src/even...
    • querySelectorAll() live collection değildir; bu yüzden sıkça doğrudan diziye çevrilerek şöyle kullanılır
      dqsA = s => Array.from(document.querySelectorAll(s));
      Böylece sonuç üzerinde .map() veya .filter() gibi dizi metotlarını doğrudan kullanabilir, jQuery’ye benzer bir his elde edersiniz
    • Yakın zamanda React bağımlılığını kaldırmayı denedim; ancak olay işleme tarafında tarayıcılar arası farklar hâlâ epey büyüktü
      Örneğin test sırasında Safari’de bir öğenin select olayı hiç tetiklenmedi, bazı tarayıcılarda ise yalnızca imleç konumu değiştiğinde olay oluşmadı
      Component, state, props gibi React özelliklerine ihtiyaç olmasa bile yalnızca yerel tarayıcı fonksiyonları yeterli değildi; React DOM’un tarayıcı farklarını örtme değeri ortaya çıktı
    • bling.js’e benziyor: https://gist.github.com/paulirish/12fb951a8b893a454b32
  • Polyfill’lerin neredeyse tamamını kaldırdıktan sonra jQuery’nin geriye kalan kalıcı avantajının otomatik liste işleme olduğunu düşünüyorum
    Bir formdaki tüm düğmelerin seçimini tek bir çağrıyla kaldırabilme yeteneğini başka yerde yakalamak hâlâ zor; üst öğe sorguları için de durum aynı
    Ancak implementasyon açısından en büyük sorun, liste boş olduğunda sessizce başarısız olması
    DOM ağacını sonradan yerleşim amaçlarıyla refactor ederken ortaya çıkan bu tür çok fazla hatayı düzelttiğim için, jQuery’yi bugün yeniden yapsaydım varsayılan olarak boş kümede hata verdirir, gerçekten umursamadığımda sessizce başarısız olması için zincir çağrı veya bayrak koyardım
    Geçmişte Sizzle’ı çıkarıp bunu bu şekilde değiştirebilir miyim diye birkaç saat incelemiştim ama daha ileri gitmedim
    Sonuçta jQuery, kütüphane mi framework mü şeklindeki eski tartışmayla da bağlantılı; dev framework’lerle uzun süre tek sayfa uygulamaları yaptıktan sonra yeniden bir hayal kırıklığı vadisine yaklaşıldığı hissi var

    • Hangi seçicinin gerçek öğelerle eşleştiğini dert etmek zorunda olmamak birçok kişi için jQuery’nin çekiciliği
      .foo öğelerinin hepsini gizle dendiğinde varsa gizlenir, yoksa hiçbir şey olmaz; CSS’e benzeyen bir fire and forget yaklaşımıdır
      .foo { color: red; } yazdığınızda belgede .foo olmasa bile küçük bir overhead dışında yan etki oluşmaz
    • Modern tarayıcılarda sorgu sonucundaki tüm öğeleri değiştirmek de tek satırda oldukça temiz yapılabiliyor
      document.querySelectorAll('input[type=checkbox]').forEach((i) => i.checked = false);
      Bu, üzerinde yineleme yapılabilen NodeList ve iterator yardımcılarından yararlanan bir yaklaşım
      Birçok üst öğe sorgusu element.closest() ile halledilebilir
    • Varsayılanın katı olması gerektiğine tamamen katılıyorum
      jQuery tabanlı kodda tüm geliştiricilerin projedeki tüm seçicileri bilmesi ve DOM değiştiğinde bunları güncellemesi gerekir ki bu elbette imkânsız
      jQuery başlatma fonksiyonunu kendi implementasyonunuzla değiştirip uzunluk kontrolünü zorunlu kılmak mümkün görünüyor
  • Ana akım web siteleri kelimenin tam anlamıyla megabaytlarca JavaScript dağıtırken, 50KB tasarruf etmek için daha az özellikli bir kütüphaneyi baştan yazmanın neden gerekli olduğunu anlamıyorum

    • Bu paketin kendisinden bağımsız olarak, jQuery tartışmalarında bu mantığı her gördüğümde şaşırıyorum
      Birçok yazı paket boyutu ve bant genişliği kısıtları nedeniyle jQuery kullanımına karşı çıkarken, aynı anda çok daha fazla bant genişliği kullanan SPA framework’lerini savunuyor
      Tamamen saçma bir cargo cult akıl yürütmesi
    • Bu mantık kulağa “ana akım fast food zincirleri 1600 kalorilik öğün satarken neden öğle yemeği için salata yapıyorsun” ya da “ulusal borç 35 trilyon dolara yaklaşmışken neden konut kredisi faizlerini karşılaştırıyorsun” demeye benziyor
      Üç durumda da cevap aynı: büyük olan şey ben değilim, ben daha küçük başka bir şey yapıyorum
      Bir diğer cevap da şu: sorun bir şeyin fazla büyük olmasıysa, daha küçük olmak çözüm gibi durur
      Sonuçta asıl sormak istenen şey geliştiricinin neden bir kütüphaneyi yeniden yazmaya zaman harcadığı gibi görünüyor; ama bu o kadar şaşırtıcı değil
      Programlamanın önemli bir kısmı zaten yapılmış şeyleri yeniden yapmakla geçer; iş gerektirdiği için, biraz farklı davranış veya performans özellikleri gerektiği için ya da sadece nasıl çalıştığını öğrenmek istendiği için yapılır
    • “Neden uğraşalım?” demek yerine küçük bağımlılıkları kabul ederseniz, bağımlılıklar da daha küçük hale gelebilir
    • Ana akım web siteleri reklam dağıtım çöplüğüne daha yakın; yapmamız gereken iş için ölçüt alınmamalılar
    • Hâlâ toplam JavaScript’i 50KB altında göndermeye çalışan insanlar var
  • jQuery alternatifi arıyorsanız, jQuery 4.0’ı çok uzun süre bekledikten sonra sonunda bazı önemli farkları olan, kendi jQuery benzeri aracımı yaptım.
    Animasyonlar, tween’ler ve timeline’lar için jQuery’nin özel sistemi yerine saf CSS kullanıyor; tekil öğeleri ve listeleri şeffaf biçimde ele alıyor ve inline kullanıma yöneliyor.

    • Dokümanlar birbiriyle çelişiyor.
      me() için 1 öğe döndürdüğü ya da ilk öğeyi veya null döndürdüğü yazıyor; any() içinse bir dizi veya boş dizi döndürdüğü belirtilmiş.
      Ama aşağıdaki örnekler any('button')?.forEach(...), any('button')?.map(...) gibi kullanımlarla null olabileceğini ima ediyor.
      any() üstteki açıklamadaki gibi her zaman dizi mi döndürüyor, yoksa alttaki örneklerdeki gibi null da mümkün mü, kafa karıştırıyor.
    • Güzel.
      Özellikle davranışın yerelliği ilgimi çekiyor.
      currentScript.parentElement kullanma deneyiminizin nasıl olduğunu merak ediyorum.
      Geçen ay hızlıca araştırdığımda, muhtemelen uç durumlarda güvenilir olmadığı izlenimini edinmiştim; ama tam olarak hangi durum olduğunu hatırlamıyorum.
      Derinlemesine incelemedim ve bunu düzgün çalışır hale getirmiş olmanıza sevindim.
      async ya da module olmadığı varsayımıyla, art arda 3 script yüklense bile tüm tarayıcılarda currentScript.parentElement hâlâ çalışmalı değil mi diye düşünüyorum.
      SvelteKit de bu tartışmayı yaptı ve sonunda hedef öğeyi belirtmek için rastgele ID uyguladı: https://github.com/sveltejs/kit/issues/2221
  • Migrasyon rehberine bakarken jQuery’nin yapabildiği ama Cash’in yapamadığı özellikler arasında, bilmediğim ve bir gün kullanmaya değer olabilecek birkaç şey öğrendim.
    https://github.com/fabiospampinato/cash/blob/master/docs/mig...

  • Genişletme hedefi olarak, TypeScript template string sihrini kullanıp öğe tipini doğru biçimde çıkarabilse iyi olurdu.
    Örneğin $('div#name') ifadesinin HTMLDivElement olduğunu statik olarak çıkarabilir.

    • O paketin adı typed-query-selector.
      Gerçek kullanım örneği burada: https://github.com/GoogleChrome/lighthouse/blob/main/types/i...
    • Elixir ve bazı diller bunu pattern matching ve tip sistemiyle yapabiliyor, ama birçok dilde durum böyle değil.
      TypeScript’te bunun mümkün olup olmadığını bilmiyorum ve nasıl yapılabileceğini pek göremiyorum.
  • jQuery 4’ün modern tarayıcılar için bir jQuery alternatifi olduğunu duymuştum.

  • Geliştirdiğim tarayıcı uzantısında başta bunu kullandım, ama sonunda bir JSX kütüphanesine geçtim.
    “Basit uygulama” alanının ötesine geçildiğinde jQuery çok hızlı şekilde akıl yürütmesi zor koda dönüşüyor; jQuery’den ilham alan bir kütüphaneyi bizzat yapmış biri olarak da böyle hissediyorum.
    Sonuçta işe uygun aracı kullanmak gerekiyor.
    [1]: https://github.com/aleclarson/dough
    Orta-büyük ölçekli uygulamalarda jQuery’yi iyi idare edebiliyorsanız sorun yok, ama benim tercihim değil.

  • Eskiden JS’i azaltmaya çalışırken https://github.com/filamentgroup/shoestring kullanmıştım.
    Ana nedeni, gerçekten ihtiyaç duyulan şeyleri ekleyen özel build sunmasıydı.
    Cash’te de benzer bir özellik var gibi, ama dokümanlarda biraz daha saklı: https://github.com/fabiospampinato/cash/blob/master/docs/par...
    Kullanacak olsam önce onu denemeyi düşünürdüm.
    Yine de bugünlerde tarayıcıların sunduğu şeyleri doğrudan kullanmanın daha iyi bir tercih olduğunu hâlâ düşünüyorum.
    Gerçekten oldukça iyi ve jQuery artık mutlaka gerekli değil.
    Özellikle küçük bir jQuery alternatifi bile 6 kB iken, React benzeri bir kütüphane olan Preact’in bunun yarısı boyutunda olduğu düşünülürse bu daha da doğru.

  • Zaten var olan Web API’lerine takma ad vermekten öte ne kadar yardımcı olduğundan pek emin değilim.