मैंने HTMX से Datastar पर स्विच क्यों किया
(everydaysuperpowers.dev)- HTMX इस्तेमाल करने पर कोड की मात्रा लगभग 70% तक कम की जा सकी, लेकिन UI सिंक्रोनाइज़ेशन की समस्याओं के साथ frontend state management की जटिलता बढ़ गई
- Datastar अपनाने के बाद, रियल-टाइम multi-user application बनाते समय WebSockets के बिना भी संक्षिप्त कोड संरचना और आसान maintainability संभव हुई
- जहाँ HTMX HTML attributes के इर्द-गिर्द behavior logic को बिखेरता है, वहीं Datastar server-driven update model के ज़रिए logic की consistency और maintainability बढ़ाता है
- Datastar API में attributes कम हैं, जिससे कोड की readability और productivity बढ़ी हुई महसूस होती है
- Datastar Server-Sent Events(SSE), Web Components, CSS View Transitions जैसी web-native technologies का सक्रिय उपयोग करता है, जिससे रियल-टाइम collaboration और reusable component structure संभव होती है
परिचय और प्रेरणा
- 2022 में David Guillot ने DjangoCon Europe में React-आधारित SaaS को HTMX में बदलते हुए कोड की मात्रा लगभग 70% कम करने और features बेहतर करने का एक उदाहरण साझा किया
- इसके बाद कई टीमों ने single-page app(SPA) से multi-page hypermedia app में स्विच करते समय कोड कम होने और developer व user experience दोनों में सुधार का अनुभव किया
- लेखक ने भी HTMX से Datastar में project बदलते हुए देखा कि कोड छोटा हो गया और WebSocket या जटिल state management के बिना रियल-टाइम multi-user app बनाना संभव हुआ
स्विच करने की वजह बने मुद्दे
- FlaskCon 2025 प्रस्तुति की तैयारी के दौरान HTMX और AlpineJS को मिलाकर UI सिंक करने की कोशिश की, लेकिन UI synchronization की समस्या सामने आई
- दोनों लाइब्रेरी अलग-अलग डेवलपर्स द्वारा बनाए गए अलग टूल हैं, इसलिए वे आपस में communicate नहीं कर पातीं, और integration का काम डेवलपर को खुद करना पड़ता है
- अलग-अलग समय पर components initialize करना और events को coordinate करना, उम्मीद से ज़्यादा कोड और debugging time लेने लगा
- Datastar दोनों लाइब्रेरी की क्षमताओं को जोड़ते हुए भी 11KB से कम आकार में मिलता है, इस बात ने ध्यान खींचा और इसे आज़माया गया
- यह mobile users के लिए page-load performance बेहतर करने में फायदेमंद है
Datastar का बेहतर API डिज़ाइन
- Datastar का API, HTMX की तुलना में काफी हल्का महसूस होता है, और मनचाहा परिणाम पाने के लिए कम attributes जोड़ने पड़ते हैं
- HTMX में ज़्यादातर interactions के लिए कई attributes चाहिए होते हैं
- URL define करना, target element तय करना, response handling का तरीका सेट करना — ये सब अलग-अलग attributes से करना पड़ता है
- आम तौर पर हर बार 2~3 attributes उपयोग होते हैं, और कभी-कभी inheritance chain ऊपर तक जाकर यह देखना पड़ता है कि attribute कैसे काम कर रहा है
<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 आम तौर पर सिर्फ एक attribute से वही काम कर देता है
<a data-on-click="@get('/rebuild/status-button')"></a>- कुछ महीनों बाद कोड दोबारा देखने पर भी उसका व्यवहार आसानी से समझा जा सकता है
काम करने के तरीके में अंतर
- HTMX एक frontend library है जिसका लक्ष्य HTML spec का विस्तार करना है, जबकि Datastar एक server-driven library है जिसका लक्ष्य high-performance web-native रियल-टाइम update application बनाना है
- HTMX, request trigger करने वाले element पर attributes जोड़कर behavior define करता है, इसलिए चाहे पेज के दूर मौजूद elements को update करना हो, logic कई layers में बिखर जाता है
- Datastar में server तय करता है कि क्या बदलना है, इसलिए सारी update logic एक जगह केंद्रित रहती है
-
HTMX उदाहरण
<div> <div id="alert"></div> <button hx-get="/info" hx-select="#info-details" hx-swap="outerHTML" hx-select-oob="#alert"> Get Info! </button> </div>- बटन दबाने पर
/infoको GET request भेजी जाती है, response केinfo-detailsID वाले element से बटन बदल दिया जाता है, और response केalertID वाले element से पेज के उसी ID वाले element को replace किया जाता है - बटन element को बहुत ज़्यादा जानकारी पहले से जाननी पड़ती है, और server क्या लौटाएगा यह भी पहले से पता होना चाहिए, इसलिए HTMX का "locality of behavior" सिद्धांत कमजोर पड़ जाता है
- बटन दबाने पर
-
Datastar का बेहतर तरीका
<div> <div id="alert"></div> <button id="info-details" data-on-click="@get('/info')"> Get Info! </button> </div>- server वही ID रखने वाले दो root elements शामिल करते हुए HTML string लौटाता है
<p id="info-details">These are the details you are looking for…</p> <div id="alert">Alert! This is a test.</div> - यह सरल और performance के लिहाज़ से बेहतर विकल्प है
- server वही ID रखने वाले दो root elements शामिल करते हुए HTML string लौटाता है
component स्तर पर सोचना
- बेहतर तरीका यह है कि HTML को components की तरह माना जाए
- उस component की असल प्रकृति को समझा जाए
- यूज़र किसी खास item के बारे में अतिरिक्त जानकारी कैसे प्राप्त करता है
- यूज़र बटन क्लिक करे तो जानकारी दिखाई देती है, या जानकारी न होने पर error render होती है; दोनों ही स्थितियों में component एक स्थिर state में पहुँच जाता है
-
state के हिसाब से component अलग करना
- placeholder state:
<!-- info-component-placeholder.html --> <div id="info-component"> <button data-on-click="@get('/product/{{product.id}}/info')"> Get Info! </button> </div> - information display state:
<!-- info-component-get.html --> <div id="info-component"> {% if alert %}<div id="alert">{{ alert }}</div>{% endif %} <p>{{product.additional_information}}</p> </div> - server HTML render करता है और Datastar पेज को अपने-आप update कर देता है
- component-level सोच गलत state में जाने या user state खो देने से बचाती है
- placeholder state:
कई components को एक साथ update करना
- David Guillot की प्रस्तुति में प्रभावशाली बात यह थी कि जब app पसंदीदा items की संख्या update करता था, तो बदला हुआ component और उससे बहुत दूर मौजूद count element भी साथ में update हो जाता था
- HTMX में इसके लिए JavaScript event trigger करना पड़ता है, जो फिर remote component पर GET request trigger करता है
- Datastar में synchronous function के भीतर भी कई components को एक साथ update किया जा सकता है
-
shopping cart उदाहरण
- cart में item जोड़ने वाला component:
<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> - cart count दिखाने वाला component:
<div id="cart-count"> <svg viewBox="0 0 10 10" xmlns="http://www.w3.org/2000/svg"> <use href="#shoppingCart"> </svg> {{count}} </div> - Django में एक ही request से दोनों components update करना:
from datastar_py.consts import ElementPatchMode from datastar_py.django import ( DatastarResponse, ServerSentEventGenerator as SSE, ) def add_item(request): # महत्वपूर्ण state update छोड़ा गया 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)) ), ])
- cart में item जोड़ने वाला component:
web-native दर्शन
- Datastar Discord community के माध्यम से यह समझ आया कि Datastar सिर्फ helper script नहीं, बल्कि web के मूल primitives का उपयोग करके app बनाने की philosophy है
- जहाँ HTMX HTML spec को आगे बढ़ाने की कोशिश करता है, वहीं Datastar web-native features को अपनाने में ज़्यादा रुचि रखता है
- CSS view transitions
- Server-Sent Events
- Web Components आदि
- जटिल AlpineJS components को refactor करके सरल Web Components निकालना और उन्हें कई जगह reuse करना एक बड़ी उपलब्धि रही
- React जैसे tools के बिना भी custom HTML elements बनाकर उच्च locality of behavior और reusability हासिल करने का यह एक शानदार pattern है
multi-user apps के लिए रियल-टाइम updates
- collaboration को first-class feature की तरह रखने वाले apps अलग दिखते हैं, और Datastar इस चुनौती को हल करता है
- ज़्यादातर HTMX developers या तो polling के ज़रिए server से जानकारी लेते हैं, या custom WebSocket code लिखकर complexity बढ़ा देते हैं
- Datastar Server-Sent Events(SSE) नाम की एक सरल web technology का उपयोग करता है, जिससे server connected clients को updates "push" कर सकता है
- यूज़र comment जोड़ता है या state बदलती है, तो server तुरंत browser update कर देता है, और अतिरिक्त कोड बहुत कम लगता है
- custom JavaScript के बिना भी रियल-टाइम dashboard, admin panel और collaboration tools बनाए जा सकते हैं
- अगर client connection टूट जाए, तो browser अपने-आप reconnect की कोशिश करता है, और इसके लिए अतिरिक्त कोड नहीं चाहिए
- server को "last received event" भी बताया जा सकता है
अनावश्यक जटिलता से बचना
- Datastar Discord community ने web apps बनाने को लेकर Datastar की सोच समझने में मदद की
- push-based UI updates
- complexity में कमी
- Web Components जैसे tools से local complex situations संभालना
- community नए users को यह समझने में मदद करती है कि वे कहीं ज़रूरत से ज़्यादा जटिल approach तो नहीं अपना रहे
मुख्य सुझाव
- पूरे component को फिर से render करके भेजने से डरना नहीं चाहिए
- यह आसान है और performance पर बड़ा असर नहीं डालता
- बेहतर compression मिल सकती है, और browser HTML string को बहुत तेज़ी से parse करता है
- server ही source of truth है, और वह browser से ज़्यादा शक्तिशाली है
- ज़्यादातर state server को संभालने दें; संभव है कि आपको उतने reactive signals की ज़रूरत ही न पड़े जितना आप सोचते हैं
- Web Components ऐसे custom elements में logic encapsulate करने के लिए बेहतरीन हैं जिनमें locality of behavior ऊँची हो
- Datastar website के header का starfield animation इसका अच्छा उदाहरण है
<ds-starfield>element starfield animation का सारा कोड encapsulate करता है और internal state बदलने के लिए तीन attributes expose करता है- Datastar range input बदलने या mouse के element पर move करने पर उन attributes को drive करता है
सीमाओं से आगे की संभावनाएँ
- Datastar जो संभावनाएँ खोलता है, वही सबसे रोमांचक हिस्सा है
- community नियमित रूप से ऐसे projects बनाती है जो दूसरे tools इस्तेमाल करने वाले developers की सीमाओं से बहुत आगे जाते हैं
उल्लेखनीय उदाहरण
- example page पर database monitoring demo
- Hypermedia का उपयोग करके JavaScript conference में दिखाए गए demo की speed और memory usage में बड़ा सुधार किया गया
- Anders Murphy का 1 billion checkboxes
- जब 1 million checkboxes वाला प्रयोग server capacity से बाहर चला गया, तो Datastar का उपयोग करके कम लागत वाले server पर 1 billion checkboxes लागू किए गए
- एक web app जो अमेरिका के सभी radar stations का data दिखाता है
- radar signal बदलते ही UI का संबंधित point 100 milliseconds के भीतर बदल जाता है
- प्रति सेकंड 800,000 से अधिक points update होते हैं, और user अधिकतम 1 घंटे पीछे तक scrub कर सकता है (700 milliseconds से कम latency)
- एक Hypermedia app के रूप में यह संभव होना दिखाता है कि Datastar क्या-क्या सक्षम कर सकता है
वर्तमान उपयोग अनुभव
- अभी भी Datastar को explore करने के चरण में हूँ, और standard HTMX-style UI update AJAX handling को जल्दी और आसानी से implement कर पा रहा हूँ
- Datastar से और अधिक हासिल करने के लिए अलग-अलग patterns सीख रहा हूँ और प्रयोग कर रहा हूँ
- दशकों से रियल-टाइम updates के माध्यम से बेहतर user experience देने के तरीकों में रुचि रही है, और Datastar का synchronous code में भी push-based updates संभव बनाना अच्छा लगता है
- HTMX का उपयोग शुरू करते समय जो बड़ा आनंद महसूस हुआ था, Datastar पर आने के बाद ऐसा नहीं लगा कि कुछ खोया है; बल्कि काफी ज़्यादा हासिल हुआ महसूस होता है
- अगर HTMX इस्तेमाल करते हुए आपको खुशी मिली थी, तो Datastar में भी वही छलांग फिर महसूस होगी — जैसे web को उसका मूल काम करते हुए फिर से खोज लेना
2 टिप्पणियां
Datastar - इंटरैक्टिव वेब ऐप्स बनाने के लिए एक हल्का हाइपरमीडिया फ्रेमवर्क
Hacker News की राय
hx-trigger="click"हटा दें तो 20% attributes कम हो जाते हैं। और<span>की जगह<button>जैसे अधिक accessible HTML का उपयोग किया जाए तो तर्क और विश्वसनीय लगेगा। आखिरकार Datastar की ताकत यह लगती है कि Alpine या Stimulus जैसी क्षमताएँ इसमें built-in हैं, और यह वाकई प्रभावशाली हैx=123&y=456आदि) के साथ अपने-आप update करने के लिएdata-replace-urlजैसा कोई option होता, तो और अच्छा लगता<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>शायद इस तरह के datastar code में बदलता है:<span data-on-click="@get('/rebuild/status-button')"></span>और आगे के दूसरे examples तो और भी उलझाने वाले हैं। आखिर htmx से Datastar पर जाने की वजह मुझे समझ नहीं आती/rebuild/status-buttonसे HTML लाओ, फिर लौटे हुए HTML में से#rebuild-bundle-status-buttonelement चुनो और मौजूदा element को replace करो।” जबकि Datastar का मतलब है: “span पर click होने पर/rebuild/status-buttonसे मिले निर्देशों का पालन करो।” अगर server कई ID वाले elements लौटाता है, तो Datastar उन्हें पहचानकर संबंधित elements को अपने-आप replace कर देता है। यानी target, select, swap सब लिखने की ज़रूरत नहीं; सिर्फ ID होने से इच्छित behavior मिल जाता हैspantag क्यों इस्तेमाल किया जा रहा है, यह समझ नहीं आता।buttonया link tag ज़्यादा उचित नहीं होगा?grugs around the fireessay पढ़ने की सिफारिश करता हूँhtmx-swap-oob="true"अनिवार्य है, वरना यह अपेक्षा के अनुसार काम नहीं करता 2. उल्टा, अगर OOB नहीं है तोhtmx-swap-oob="true"होने पर वह ignore हो सकता है या गड़बड़ कर सकता है। इस वजह से एक ही component को OOB/non-OOB दोनों रूप में reuse करने के लिए server से हर बारisOobflag भेजना पड़ता है, जो बहुत झंझट है