Svelte 5, Javascript नहीं है
(hodlbod.npub.pro)- हाल ही में एक web application को Svelte 5 version में upgrade करने के बाद सामने आए issues का सारांश
- deep reactivity feature और बदले हुए lifecycle के कारण अप्रत्याशित behavior देखने को मिला
- Svelte 3/4 का लंबे समय तक आनंद लिया, लेकिन आगे नए projects के लिए शायद Svelte नहीं चुनूंगा
तेज़ गति की ज़रूरत
- Svelte team ने deep reactivity के ज़रिए performance optimization की कोशिश की, और बेहतर performance हासिल की
- पहले भी compiler process के माध्यम से तेज़ performance मिलती थी, और यही दूसरी frameworks से अलग इसकी ताकत थी
- इससे framework opaque हो गया और debugging मुश्किल हुई, लेकिन performance और productivity के लिहाज़ से यह स्वीकार्य trade-off लगा
तेज़ गति की ज़रूरत
- Svelte 5 में Svelte team का मुख्य बदलाव “deep reactivity” है, जिसका उद्देश्य अधिक granular reactivity के जरिए performance बढ़ाना है
- Svelte के पहले के versions में यह लक्ष्य मुख्य रूप से Svelte compiler के जरिए हासिल किया जाता था
- developers को नए concepts सीधे सीखने की ज़रूरत नहीं पड़ती थी, और internal logic को फिर से व्यवस्थित करना आसान था; यही Svelte की विशिष्टता थी
- साथ ही, यही compile process framework को opaque बनाती थी, जिससे complex issues की debugging कठिन हो जाती थी
- compiler के bug के कारण ऐसे errors आते थे जिनका root cause समझना मुश्किल होता था, और कभी-कभी problematic component को पूरी तरह refactor करना ही एकमात्र समाधान बचता था
- फिर भी speed और productivity के लिहाज़ से यह एक उचित trade-off लगा, इसलिए projects को समय-समय पर reset करने की असुविधा भी स्वीकार की गई
Svelte, Javascript नहीं है
- Svelte 5 इस trade-off को दोगुना कर देता है
- मुख्य अंतर यह है कि abstraction और performance के बीच का समझौता compile stage से आगे बढ़कर runtime तक पहुँच गया है
- deep reactivity को support करने के लिए Proxy का उपयोग
- implicit component lifecycle state
- ये दोनों बदलाव performance बेहतर करते हैं और developer API को अधिक slick दिखाते हैं
- इसमें नापसंद करने जैसा क्या हो सकता है? दुर्भाग्य से, ये दोनों features leaky abstraction के क्लासिक उदाहरण हैं
- अंततः ये developers के लिए काम करने का माहौल और अधिक जटिल बना देते हैं
Proxies, objects नहीं हैं
- Proxy के उपयोग से Svelte team framework performance को थोड़ा और बढ़ा सकी, बिना developers से अतिरिक्त काम कराए
- React जैसी frameworks में कई components के बीच state pass करने पर अक्सर अनावश्यक rerendering होती है; Svelte ने इसे कम करने के लिए Proxy अपनाया
- Svelte compiler पहले से ही virtual DOM diffing में आने वाली कुछ समस्याओं से बचता था, लेकिन लगता है कि Proxy से performance और बेहतर की जा सकती थी
- Svelte team ने यह भी कहा कि Proxy developer experience को बेहतर बनाता है, और दावा किया कि इससे “efficiency और ease of use दोनों को अधिकतम किया जा सकता है”
- समस्या यह है कि Svelte 5 ऊपर से अधिक सरल दिखता है, लेकिन वास्तव में यह और अधिक abstraction जोड़ता है
- उदाहरण के लिए, array methods detect करने के लिए Proxy इस्तेमाल करने से Svelte 4 की तरह
value = valueलिखने की ज़रूरत नहीं रहती - Svelte 4 में reactivity trigger करने के लिए developers को compiler के काम करने के तरीके की कुछ समझ होनी ही पड़ती थी। इसके विपरीत, Svelte 5 यह आभास देता है कि “अब compiler को भूल सकते हैं”, जबकि वास्तव में ऐसा नहीं है
- नई abstraction से मिली सुविधा के साथ-साथ वे नियम भी बढ़ गए हैं जिन्हें developers को समझना पड़ता है ताकि compiler मनचाहा व्यवहार करे
- उदाहरण के लिए, array methods detect करने के लिए Proxy इस्तेमाल करने से Svelte 4 की तरह
- लंबे समय तक Svelte इस्तेमाल करते हुए, व्यक्तिगत रूप से मैंने धीरे-धीरे Svelte store का अधिक उपयोग किया और reactive declarations का कम
- Svelte store मूल रूप से Javascript concepts के ज्यादा करीब है,
updatemethod को call करना सीधा है, और$syntax बस एक अतिरिक्त लाभ जैसा था - Proxy भी reactive declarations की तरह वही समस्या पैदा करता है: “दिखने में एक चीज़, लेकिन boundary पर जाकर अलग तरह से काम करना”
- Svelte store मूल रूप से Javascript concepts के ज्यादा करीब है,
- Svelte 5 को पहली बार इस्तेमाल करते समय सब कुछ ठीक चला, लेकिन जब Proxy state को IndexedDB में store करने की कोशिश की तो
DataCloneErrorआया- और भी मुश्किल यह है कि किसी value के Proxy होने की पुष्टि करने के लिए structured clone को
try/catchमें आज़माना पड़ता है, जिसकी performance cost भी है - अंततः यह याद रखना पड़ता है कि क्या Proxy है, और ऐसे external contexts में जहाँ Proxy को पहचाना नहीं जाता, हर बार
$state.snapshotइस्तेमाल करना पड़ता है - नतीजतन, “abstraction developer convenience बढ़ाती है” इस मूल इरादे के उलट, developers पर और अधिक जटिल नियम और प्रक्रियाएँ लाद दी जाती हैं
- और भी मुश्किल यह है कि किसी value के Proxy होने की पुष्टि करने के लिए structured clone को
Components, functions नहीं हैं
- लगभग 2013 के आसपास virtual DOM के लोकप्रिय होने का एक बड़ा कारण यह था कि applications को function composition के रूप में model किया जा सकता था
- Svelte ने virtual DOM की जगह compiler का उपयोग करके lifecycle functions को सरल और performance को ऊँचा बनाए रखा
- लेकिन Svelte 5 में lifecycle का concept फिर से React Hooks जैसा होकर लौट आया है
- React में Hooks lifecycle methods से जुड़े state logic को कम करने वाली abstraction हैं
- code साफ़ दिखता है, लेकिन
setTimeoutमें state refer करने जैसी स्थितियों में developers को बहुत सावधान रहना पड़ता है - Svelte 4 में भी component unmount होने के समय यदि async code DOM element को access करे तो समस्या हो सकती थी
- अब Svelte 5 में लगता है कि state changes और effects को coordinate करने के लिए component lifecycle में implicit state जोड़ दी गई है
- code साफ़ दिखता है, लेकिन
- $effect के official docs में इसे इस तरह समझाया गया है:
“$effect को कहीं भी रखा जा सकता है, लेकिन इसे component initialization के दौरान (या जब parent effect active हो) call किया जाना चाहिए, और component (या parent effect) unmount होने पर यह समाप्त हो जाता है”
- यह उस व्याख्या के विपरीत संकेत देता है कि lifecycle में सिर्फ mount/unmount के दो चरण हैं; यानी वास्तव में एक अधिक जटिल effect structure मौजूद है जिसे state changes के साथ track करना पड़ता है
- official lifecycle docs में कहा गया है कि “before update/after update नहीं है”, लेकिन
$effect.preऔरtickजैसे नए concepts सामने आते हैं - इसका अर्थ है कि mount/unmount के अलावा state change के timing को समझना भी आवश्यक है
- वास्तविक उपयोग में समस्या यह थी कि Svelte से असंबंधित function को दी गई state भी component lifecycle से बंधी रहती है
- उदाहरण के लिए, modal window को store से manage करते हुए callback को child component में pass करने का pattern इस्तेमाल किया गया
const { value } = $props() const callback = () => console.log(value) const openModal = () => pushModal(MyModal, { callback }) - अगर यह code modal component के अंदर है, तो modal को call करने वाला component पहले unmount हो जाता है, और उसी समय
valueundefined में बदल जाता है - इस repository में इसका minimal reproduction example उपलब्ध है
- यानी, component lifecycle खत्म होने के बाद भी जीवित callback जिस props को refer कर रहा था, वह अचानक undefined हो जाता है
- यह सामान्य Javascript से अलग behavior है, और ऐसा लगता है जैसे Svelte खुद कोई garbage collection जैसा काम कर रहा हो
- इसके पीछे engineering कारण होंगे, लेकिन यह behavior अप्रत्याशित होने के कारण चौंकाता है
निष्कर्ष
- आसान चीज़ें निस्संदेह आकर्षक होती हैं, लेकिन Rich Hickey के शब्दों में easy का मतलब simple नहीं होता
- Joel Spolsky की तरह, अप्रत्याशित behavior होना पसंद नहीं है
- Svelte ने अब तक बहुत “magic” दिखाया है, लेकिन इस version में उस magic का उपयोग करने के लिए इतना कुछ याद रखना पड़ता है कि लाभ से अधिक बोझ महसूस होता है
- इस लेख का उद्देश्य Svelte team को दोष देना नहीं है; बल्कि यह स्वीकार करना है कि Svelte 5 (और React Hooks) को पसंद करने वाले लोग भी बहुत हैं
- महत्वपूर्ण बात यह है कि users को convenience देने और users के हाथ में control बनाए रखने के बीच संतुलन हो
- सचमुच अच्छा software “cleverness” पर नहीं, बल्कि “understanding” पर आधारित होता है
- जैसे-जैसे AI tools विकसित हो रहे हैं, यह और महत्वपूर्ण हो जाता है कि हम ऐसे tools चुनें जो हमें यह न भुलाएँ कि हम क्या कर रहे हैं, बल्कि हमारी पहले से संचित समझ का उपयोग करें और गहरी समझ को बढ़ाएँ
- Rich Harris और team को अब तक के आनंददायक development experience के लिए धन्यवाद। आशा है यह लेख पूरी तरह गलत नहीं, बल्कि उपयोगी feedback साबित होगा
7 टिप्पणियां
proxy बनाने वाले के लिए तो यह सुविधाजनक होता है, लेकिन डिबग करने वाले को गुस्सा आ जाता है lol
साइड प्रोजेक्ट में solidjs का DX नंबर वन है >m< / बहुत खुशी
मुझे लगता है कि svelte जैसे विकल्प मौजूद थे, इसलिए React/nextjs को भी काफ़ी बड़ा प्रोत्साहन मिला होगा।
मूल रूप से svelte एक language है, इसलिए उम्मीद है कि यह UI को व्यक्त करने वाली भाषा को आगे किस दिशा में जाना चाहिए, यह भी अच्छी तरह दिखाएगा।
मैं तो React ही इस्तेमाल करूंगा
अति सर्वत्र वर्जयेत
भ्रम में पड़ जाना
ऊपर से ऊपर चढ़ाई गई परत
मुझे लगता है कि React और खासकर next के असर में यह काफ़ी बदलकर अजीब हो गया है।
+pageको svelte जाने बिना देखकर समझना मुश्किल है, और$state,$derivedजैसे rune React की नकल करते हुए लगते हैं; बल्कि वेरिएबल के आगे$:लगाने वाला पुराना दौर कुछ बेहतर लगता है।{#each a in array} {/each}जैसी पुरानी syntax भी किसी तरह झेली जा सकती है, लेकिन फिर भी झुंझलाहट होती है। अगर optional reactivity से performance सुधार ही मकसद है, तो मुझे लगता है solidjs कहीं बेहतर दिशा है। jsx को वैसे ही इस्तेमाल करने की वजह से react से वहाँ जाना भी अपेक्षाकृत आसान है। solidjs को अपेक्षाकृत ज़्यादा ध्यान नहीं मिल रहा, यह तो हैरानी की बात है।मुझे लगता है कि Signals, Gartner hype cycle के Trough of disillusionment की ओर बढ़ रहा है 🤔 जैसे-जैसे इसके use cases ज़्यादा स्पष्ट होते जाएंगे, शायद इसकी समीक्षा भी बेहतर हो सकती है।
Hacker News राय
शुरुआत में runes को लेकर मैं खास उत्साहित नहीं था। लेकिन जब मैंने देखा कि
.svelteटेम्पलेट में reactive external components इम्पोर्ट किए जा सकते हैं, और reactivity को अंदरूनी तौर पर encapsulate किया जा सकता है, तब मेरी राय बदल गई। इसका मतलब है कि आप vitest tests लिख सकते हैं और फिर भी reactivity के फायदे ले सकते हैं। यह सच में बहुत शक्तिशाली है, और AFAIK, frontend दुनिया में अनोखा हैमैं एक commercially deployed SvelteKit application को सक्रिय रूप से develop कर रहा हूँ, और इस अनुभव पर अपने विचार साझा करना चाहता हूँ
+pageजैसी routing structure से निपटना नहीं पड़ता था। आप Svelte files को जहाँ चाहें रख सकते थे, और फिर भी modern framework के फ़ायदों के साथ सब कुछ smoothly render हो जाता थाEmberJS का फीका पड़ जाना दुखद है। उसका API पिछले 10 साल में काफ़ी stable रहा है। विडंबना यह है कि पिछले 10 साल में EmberJS app लिखने वाले लोगों को migration में शायद React, Svelte, Vue वगैरह के साथ वही काम करने वालों से कम दिक्कत हुई होगी
लेखक ने पोस्ट के ऊपर जो दो Github links दिए हैं, वे एक ही issue की ओर इशारा करते हैं, और उस issue का solution है (
use $state.raw)Svelte 5 JavaScript नहीं होने का <i>सबसे खराब</i> तरीका है। यह js की समस्याएँ हल नहीं करता, बल्कि कुछ frontend समस्याओं के लिए leaky abstractions देता है। मुझे लगता है कि Solid, Svelte से बेहतर दिशा है। क्योंकि Solid किसी नई language पर निर्भर नहीं करता। लेकिन चूँकि js आदर्श नहीं है, इसलिए कुछ non-js बनाने की प्रवृत्ति समझ में आती है। Elm, svelte का पूर्वज है। लेकिन मुझे लगता है कि इससे भी बेहतर कुछ बनाया जा सकता है...[0]
मैंने Svelte 5 इस्तेमाल करना इसलिए शुरू किया क्योंकि मुझे Svelte 4 में stores सचमुच नापसंद थे। मैं एक नए project में Sveltekit और Svelte 5 का इस्तेमाल कर रहा हूँ, और मुझे कहना होगा... React की productivity अब भी बेजोड़ है, भले ही Sveltekit और Svelte तकनीकी रूप से बेहतर हों
+page.server.tsया+page.svelteया उनके variants के रूप में होना, जिससे code को आसानी से search करना मुश्किल हो जाता है। Svelte के tools,tscऔर ESLint से अलग अस्तित्व रखते हैं, इसलिए उन्हें CI में integrate करना और development में इस्तेमाल करना ज़्यादा कठिन हैयह कहना अजीब लगता है कि Svelte JavaScript नहीं है, सिर्फ इसलिए कि callbacks में closures पास करते समय कुछ unexpected behavior होता है। इससे बेहतर शीर्षक होता: "Svelte 5 ने मुझे चौंकाया, इसलिए मुझे यह पसंद नहीं है"
अगर आप ऐसी library ढूँढ़ रहे हैं जिससे pure JavaScript इस्तेमाल करके components और apps बनाए जा सकें, तो Lit देखें: Lit
अगर आप एक समझदार frontend experience चाहते हैं, तो vanilla Javascript, web components, htmx, Blazor इस्तेमाल कीजिए