HTMX'ten Datastar'a geçmemin nedeni
(everydaysuperpowers.dev)- HTMX kullanırken kod miktarını yaklaşık %70 azaltmak mümkün oldu, ancak UI'lar arası senkronizasyon sorunlarıyla birlikte frontend durum yönetiminin karmaşıklığının arttığı görüldü
- Datastar benimsendikten sonra, gerçek zamanlı çok kullanıcılı uygulamalar geliştirirken WebSockets olmadan daha yalın bir kod yapısı ve daha kolay bakım sağlandı
- HTMX, çalışma mantığını HTML öznitelikleri etrafında dağıtırken, Datastar sunucu güdümlü güncelleme modeli ile mantığın tutarlılığını ve bakım kolaylığını artırıyor
- Datastar API'sinde daha az öznitelik bulunuyor; bunun da kodun okunabilirliğini ve üretkenliği artırdığı hissediliyor
- Datastar, Server-Sent Events(SSE), Web Components, CSS View Transitions gibi web-native teknolojileri etkin biçimde kullanarak gerçek zamanlı iş birliğini ve yeniden kullanılabilir bileşen yapısını mümkün kılıyor
Giriş ve motivasyon
- 2022'de David Guillot, DjangoCon Europe'ta React tabanlı bir SaaS'ı HTMX'e geçirerek kod miktarını yaklaşık %70 azalttıkları ve işlevleri geliştirdikleri bir örneği paylaştı
- Ardından birçok ekip, tek sayfa uygulamalardan (SPA) çok sayfalı hypermedia uygulamalarına geçerken hem kodun azaldığını hem de geliştirici ve kullanıcı deneyiminin iyileştiğini gördü
- Yazar da kendi projesini HTMX'ten Datastar'a geçirirken, kodun daha kısa hale geldiğini ve WebSocket ya da karmaşık durum yönetimi olmadan gerçek zamanlı çok kullanıcılı uygulamalar geliştirilebildiğini doğruladı
Geçişi tetikleyen sorunlar
- FlaskCon 2025 sunumunu hazırlarken, HTMX ve AlpineJS'i birleştirerek UI'ı senkronize etmeye çalıştı ancak senkronizasyon sorunlarıyla karşılaştı
- İki kütüphane de farklı geliştiriciler tarafından yapılmış ayrı araçlar olduğu için birbirleriyle iletişim kuramıyor, entegrasyonu geliştiricinin kendisinin yapması gerekiyor
- Bileşenleri farklı anlarda başlatmak ve olayları koordine etmek, beklenenden çok daha fazla kod yazımı ve hata ayıklama süresi gerektirdi
- Datastar'ın bu iki kütüphanenin işlevlerini birleştirirken 11KB'den küçük bir boyutta sunulmasına dikkat çekildi ve denenmeye karar verildi
- Bu, mobil cihaz kullananlar için sayfa yükleme performansı açısından avantaj sağlıyor
Daha iyi bir Datastar API tasarımı
- Datastar API'si, HTMX'e kıyasla çok daha hafif bir his veriyor ve istenen sonucu almak için eklenmesi gereken öznitelik sayısı daha az
- HTMX, çoğu etkileşim için birden fazla öznitelik gerektiriyor
- URL tanımı, hedef öğenin belirtilmesi ve yanıtın nasıl işleneceği gibi ayarlar ayrı ayrı özniteliklerle yapılıyor
- Genelde her seferinde 2-3 öznitelik kullanılıyor; bazen de özniteliklerin nasıl çalıştığını anlamak için kalıtım zinciri boyunca yukarı çıkmak gerekiyor
<a hx-target="#rebuild-bundle-status-button" hx-select="#rebuild-bundle-status-button" hx-swap="outerHTML" hx-trigger="click" hx-get="/rebuild/status-button"></a> - Datastar ise aynı işlevi genellikle tek bir öznitelikle gerçekleştiriyor
<a data-on-click="@get('/rebuild/status-button')"></a>- Koda aylar sonra geri dönüldüğünde bile nasıl çalıştığını anlamak kolay oluyor
Çalışma mantığındaki fark
- HTMX bir frontend kütüphanesi olarak HTML spesifikasyonunu genişletmeyi hedeflerken, Datastar sunucu güdümlü bir kütüphane olarak yüksek performanslı, web-native, gerçek zamanlı güncelleme yapan uygulamalar kurmayı hedefliyor
- HTMX, davranışı isteği tetikleyen öğeye eklenen özniteliklerle tanımlıyor; sayfanın uzağındaki başka öğeleri güncellese bile mantık farklı katmanlara dağılmış oluyor
- Datastar'da ise neyin değişeceğine sunucu karar veriyor ve tüm güncelleme mantığı tek bir yerde toplanıyor
-
HTMX örneği
<div> <div id="alert"></div> <button hx-get="/info" hx-select="#info-details" hx-swap="outerHTML" hx-select-oob="#alert"> Get Info! </button> </div>- Düğmeye basılınca
/infoadresine bir GET isteği gönderiliyor, yanıttakiinfo-detailskimliğine sahip öğe ile düğme değiştiriliyor ve yanıttakialertkimliğine sahip öğe ile sayfadaki aynı kimlikteki öğe değiştiriliyor - Düğme öğesinin bilmesi gereken şey çok fazla ve sunucunun ne döndüreceğini önceden bilmek gerektiğinden HTMX'in "locality of behavior" ilkesi zayıflıyor
- Düğmeye basılınca
-
Datastar'ın iyileştirilmiş yaklaşımı
<div> <div id="alert"></div> <button id="info-details" data-on-click="@get('/info')"> Get Info! </button> </div>- Sunucu, aynı kimliğe sahip iki kök öğe içeren bir HTML dizgesi döndürüyor
<p id="info-details">These are the details you are looking for…</p> <div id="alert">Alert! This is a test.</div> - Basit ve performansı yüksek bir seçenek
- Sunucu, aynı kimliğe sahip iki kök öğe içeren bir HTML dizgesi döndürüyor
Bileşen düzeyinde düşünmek
- Daha iyi yaklaşım, HTML'i bileşen olarak ele almak
- O bileşenin özünü kavramak gerekiyor
- Kullanıcının belirli bir öğe hakkında ek bilgiyi nasıl aldığı
- Kullanıcı düğmeye tıkladığında bilgi görünür ya da bilgi yoksa bir hata render edilir; her iki durumda da bileşen statik bir duruma geçer
-
Duruma göre bileşenleri ayırmak
- Yer tutucu durumu:
<!-- info-component-placeholder.html --> <div id="info-component"> <button data-on-click="@get('/product/{{product.id}}/info')"> Get Info! </button> </div> - Bilgi gösterme durumu:
<!-- info-component-get.html --> <div id="info-component"> {% if alert %}<div id="alert">{{ alert }}</div>{% endif %} <p>{{product.additional_information}}</p> </div> - Sunucu HTML'i render ettiğinde Datastar sayfayı otomatik olarak güncelliyor
- Bileşen düzeyinde düşünmek, geçersiz bir duruma girilmesini veya kullanıcı durumunun kaybolmasını önlüyor
- Yer tutucu durumu:
Aynı anda birden fazla bileşeni güncellemek
- David Guillot'nun sunumundaki etkileyici noktalardan biri, uygulama favori sayısını güncellerken değişen bileşenin yanı sıra ondan çok uzaktaki sayaç öğesinin de birlikte güncellenmesiydi
- HTMX burada JavaScript olayı tetikliyor ve bu olay da uzak bileşenin GET isteği göndermesini tetikliyor
- Datastar, senkron bir fonksiyon içinde bile birden fazla bileşeni aynı anda güncelleyebiliyor
-
Alışveriş sepeti örneği
- Sepete ekleme bileşeni:
<form id="purchase-item" data-on-submit="@post('/add-item', {contentType: 'form'})">" > <input type=hidden name="cart-id" value="{{cart.id}}"> <input type=hidden name="item-id" value="{{item.id}}"> <fieldset> <button data-on-click="$quantity -= 1">-</button> <label>Quantity <input name=quantity type=number data-bind-quantity value=1> </label> <button data-on-click="$quantity += 1">+</button> </fieldset> <button type=submit>Add to cart</button> {% if msg %} <p class=message>{{msg}}</p> {% endif %} </form> - Sepet sayısını gösteren bileşen:
<div id="cart-count"> <svg viewBox="0 0 10 10" xmlns="http://www.w3.org/2000/svg"> <use href="#shoppingCart"> </svg> {{count}} </div> - Django'da iki bileşeni aynı istekle güncellemek:
from datastar_py.consts import ElementPatchMode from datastar_py.django import ( DatastarResponse, ServerSentEventGenerator as SSE, ) def add_item(request): # önemli durum güncellemesi atlandı return DatastarResponse([ SSE.patch_elements( render_to_string('purchase-item.html', context=dict(cart=cart, item=item, msg='Item added!')) ), SSE.patch_elements( render_to_string('cart-count.html', context=dict(count=item_count)) ), ])
- Sepete ekleme bileşeni:
Web-native felsefesi
- Datastar Discord topluluğu sayesinde Datastar'ın sadece basit bir yardımcı script değil, web'in temel primitiflerini kullanarak uygulama kurma felsefesi olduğu anlaşıldı
- HTMX HTML spesifikasyonunu ilerletmeye çalışırken, Datastar daha çok web-native özelliklerin benimsenmesini teşvik etmeye odaklanıyor
- CSS view transitions
- Server-Sent Events
- web components vb.
- Karmaşık AlpineJS bileşenlerini refactor edip basit web components çıkararak bunları birden çok yerde yeniden kullanmak büyük bir kazanım oldu
- React gibi araçlar olmadan da özel HTML öğeleri oluşturarak yüksek davranış yerelliği ve yeniden kullanılabilirlik elde etmek çok iyi bir desen sunuyor
Çok kullanıcılı uygulamalar için gerçek zamanlı güncellemeler
- İş birliğini birinci sınıf özellik olarak sunan uygulamalar diğerlerinden ayrışıyor ve Datastar bu sorunu çözüyor
- HTMX kullanan geliştiricilerin çoğu, sunucudan bilgi almak için polling kullanıyor ya da karmaşıklığı artıran özel WebSocket kodları yazıyor
- Datastar, Server-Sent Events(SSE) adlı basit bir web teknolojisini kullanarak sunucunun bağlı istemcilere güncellemeleri "push" etmesini sağlıyor
- Kullanıcı yorum eklediğinde veya durum değiştiğinde sunucu tarayıcıyı anında güncelliyor; gereken ek kod çok az
- Özel JavaScript olmadan gerçek zamanlı dashboard'lar, yönetim panelleri ve iş birliği araçları kurulabiliyor
- İstemci bağlantısı kesilirse tarayıcı otomatik olarak yeniden bağlanmayı dener; ek kod gerekmez
- Sunucuya "en son alınan olay" bilgisini de verebilir
Aşırı karmaşıklıktan kaçınmak
- Datastar Discord topluluğu, Datastar'ın web uygulaması geliştirmeye dair vizyonunu anlamaya yardımcı oluyor
- Push tabanlı UI güncellemeleri
- Karmaşıklığın azaltılması
- Web components gibi araçlarla yerelde karmaşık durumların ele alınması
- Topluluk, yeni kullanıcıların yaklaşımı gereğinden fazla karmaşıklaştırdığını fark etmelerine de yardımcı oluyor
Temel ipuçları
- Tüm bileşeni yeniden render edip göndermekten çekinmeyin
- Bu daha kolaydır ve performansa büyük bir etkisi olmaz
- Daha iyi sıkıştırma oranı elde edilebilir, ayrıca tarayıcı HTML dizgelerini çok hızlı parse eder
- Gerçeğin durumu sunucudadır ve sunucu tarayıcıdan daha güçlüdür
- Durumun büyük bölümünü sunucu yönetsin; düşündüğünüz kadar reaktif sinyale ihtiyaç olmayabilir
- Web components, mantığı yüksek davranış yerelliğine sahip özel öğeler içinde kapsüllemek için mükemmeldir
- Datastar web sitesindeki başlıktaki yıldız alanı animasyonu buna iyi bir örnek
<ds-starfield>öğesi yıldız alanı animasyonuna ait tüm kodu kapsüllüyor ve iç durumu değiştirmek için üç öznitelik sunuyor- Datastar, range input değiştiğinde veya fare öğenin üzerinde hareket ettiğinde bu öznitelikleri sürüyor
Sınırları aşan olanaklar
- En heyecan verici olan, Datastar'ın mümkün kıldığı potansiyel
- Topluluk düzenli olarak, başka araçları kullanan geliştiricilerin yaşadığı sınırların çok ötesine geçen projeler üretiyor
Dikkat çeken örnekler
- Örnek sayfadaki veritabanı izleme demosu
- Hypermedia kullanarak, JavaScript konferanslarında sunulan demolara kıyasla hız ve bellek kullanımında büyük iyileşme sağlıyor
- Anders Murphy'nin 1 milyar checkbox projesi
- 1 milyon checkbox deneyi sunucu kapasitesini aşınca, Datastar kullanılarak düşük maliyetli bir sunucuda 1 milyar checkbox gerçekleştirildi
- ABD'deki tüm radar istasyonlarının verilerini gösteren bir web uygulaması
- Radardaki sinyal değiştiğinde UI'daki ilgili nokta 100 milisaniyenin altında değişiyor
- Saniyede 800 binden fazla nokta güncelleniyor ve kullanıcılar en fazla 1 saat öncesine kadar scrub yapabiliyor (700 milisaniyenin altında gecikmeyle)
- Bunun bir hypermedia uygulaması olarak mümkün olması, Datastar'ın neler sağladığını gösteriyor
Güncel kullanım deneyimi
- Datastar hâlâ keşif aşamasında olsa da, standart HTMX tarzı UI güncelleme AJAX işlemlerini hızlı ve kolay biçimde uygulayabiliyor
- Datastar ile daha fazlasını başarmaya yönelik çeşitli desenler öğreniliyor ve deneniyor
- Onlarca yıldır gerçek zamanlı güncellemelerle daha iyi kullanıcı deneyimi sunma yollarına ilgi duyuluyordu; Datastar'ın senkron kodda bile push tabanlı güncellemeler sağlayabilmesi beğeniliyor
- HTMX kullanılmaya başlandığında büyük bir heyecan hissedilmişti; ancak Datastar'a geçtikten sonra hiçbir şey kaybedilmediği, aksine çok daha fazlasının kazanıldığı düşünülüyor
- HTMX kullanırken aynı heyecanı hissettiyseniz, Datastar'da da benzer bir sıçramayı yeniden hissedeceksiniz; bu, adeta web'in en başta yapması gereken şeyi yeniden keşfetmek gibi
2 yorum
HTMX'ten Datastar'a neden geçildi
Hacker News görüşleri
hx-trigger="click"kaldırılırsa attribute sayısı %20 azalıyor. Ayrıca<span>yerine<button>kullanmak gibi daha erişilebilir HTML yazılsa güvenilirliği artardı. Sonuçta Datastar’ın güçlü yanı, sanki Alpine ya da Stimulus işlevlerini içine gömülü olarak sunması gibi görünüyor; bu gerçekten etkileyicix=123&y=456gibi) otomatik güncellenmesini sağlayandata-replace-urlbenzeri bir seçenek olsa daha iyi olurdu<span hx-target="#rebuild-bundle-status-button" hx-select="#rebuild-bundle-status-button" hx-swap="outerHTML" hx-trigger="click" hx-get="/rebuild/status-button"></span>şu datastar koduna dönüşüyor gibi görünüyor:<span data-on-click="@get('/rebuild/status-button')"></span>Dahası, diğer örnekler daha da kafa karıştırıcı. Sonuç olarak insanların neden htmx’ten Datastar’a geçtiğini anlamıyorum/rebuild/status-buttonadresinden HTML al, dönen HTML içinden#rebuild-bundle-status-buttonöğesini seç ve mevcut öğeyle değiştir” demek. Datastar’da ise “span’e tıklanınca/rebuild/status-buttontarafından verilen komutları uygula” anlamına geliyor. Sunucu birden fazla ID’li öğe döndürürse Datastar bunların hepsini otomatik olarak tanıyıp değiştiriyor. Yanitarget,select,swapkullanmadan, sadece ID vererek istenen davranış elde edilebiliyorspankullanılıyor, onu da anlamıyorum.buttonya da link etiketi daha uygun olmaz mı?htmx-swap-oob="true"mutlaka gerekli; bu attribute yoksa beklenmedik davranıyor 2. Tersi durumda OOB değilsehtmx-swap-oob="true"varsa ya yok sayılıyor ya da yanlış çalışıyor. Bu yüzden aynı bileşeni OOB ve OOB olmayan durumda yeniden kullanmak istediğinde sunucunun her seferindeisOobbayrağı göndermesi gerekiyor; bu da gerçekten uğraştırıcı