टर्बोलिंक्स - यह शायद रेल्स ब्रह्मांड में सबसे अधिक नफरत किए जाने वाले शब्दों में से एक है।
शायद आपने इसे आज़माया। आपने इसे नए प्रोजेक्ट या मौजूदा ऐप में शामिल किया। और जल्द ही ऐप अजीब और अद्भुत तरीकों से विफल होने लगा। अच्छी बात है कि फिक्स उतना ही आसान था - टर्बोलिंक्स बंद कर दें।
...लेकिन कुछ कंपनियां इसे काम करवाती हैं। यहां हनीबैजर पर, हमने इसे काम करवाया है - और हम कोई जीनियस नहीं हैं।
उत्तर इतना सरल है कि मैं इसे लाने में लगभग हिचकिचा रहा हूँ। लेकिन रूबी नेशन और मैडिसन+रूबी में इस विषय पर बातचीत देने के बाद, ऐसा प्रतीत होता है कि लोग इस विषय को उपयोगी पाते हैं। तो आइए खुदाई करें।
टर्बोलिंक्स और PJAX कैसे काम करते हैं

टर्बोलिंक्स और PJAX अनिवार्य रूप से उसी तरह काम करते हैं। वे इतने समान हैं, मैं अब से सिर्फ PJAX कहने जा रहा हूँ। :)
आप PJAX को दो पेज अनुरोधों के संदर्भ में समझ सकते हैं। पहली बार जब कोई उपयोगकर्ता कोई पेज अनुरोध करता है, तो यह किसी अन्य "पारंपरिक" रेल्स पेज की तरह ही परोसा जाता है। लेकिन जब उपयोगकर्ता PJAX-सक्षम लिंक पर क्लिक करता है, तो कुछ खास होता है। पूरे पेज को पूरी तरह से रीलोड करने के बजाय, पेज के केवल एक हिस्से को अपडेट किया जाता है। यह AJAX के माध्यम से किया जाता है।
यह हमें सिंगल पेज ऐप के कई फायदे देता है, जबकि कुछ कठिनाइयों को दरकिनार करता है:
- PJAX ऐप अक्सर सिंगल पेज ऐप की तरह ही तेज़ लगते हैं, क्योंकि पेज को अब हर अनुरोध पर पूरी तरह से रीलोड नहीं करना पड़ता।
- आप फ्रंट-एंड और बैक एंड डेवलपमेंट के लिए समान स्टैक का उपयोग कर सकते हैं
- PJAX ऐप डिफ़ॉल्ट रूप से ग्रेसफुल डिग्रेड होते हैं जब उपयोगकर्ता ने JS अक्षम किया हो
- PJAX ऐप को सुलभ और SEO फ्रेंडली बनाना आसान है
टर्बोलिंक्स लागू करना
बहुत सारी लाइब्रेरी हैं जो आपके लिए PJAX का भारी भार उठाएंगी। टर्बोलिंक्स शायद सबसे प्रसिद्ध है। इसे सेट करना आपके Gemfile में टर्बोलिंक्स जेम को शामिल करने की बात है:
gem 'turbolinks'
...और app/assets/javascripts/application.js में JS शामिल करना
//= require turbolinks
अब जब आप अपना ऐप रीलोड करते हैं, तो हर आंतरिक लिंक एक टर्बोलिंक होगा। जब आप उन पर क्लिक करते हैं, तो नया पेज AJAX के माध्यम से अनुरोध किया जाएगा और वर्तमान दस्तावेज़ में डाला जाएगा।
jquery-pjax लागू करना
यहां हनीबैजर पर, हम एक PJAX लाइब्रेरी का उपयोग करते हैं जिसे मूल रूप से Github द्वारा विकसित किया गया था। इसे टर्बोलिंक्स की तुलना में थोड़ा अधिक कॉन्फिगरेशन की आवश्यकता होती है, लेकिन यह काफी अधिक लचीला भी है।
यह मानने के बजाय कि सभी लिंक PJAX हैं, यह आपको इसे नियंत्रित करने देता है। यह आपको यह भी नियंत्रित करने देता है कि पेज पर PJAX कंटेंट कहां डाला जाएगा।
पहली चीज जो मुझे करने की ज़रूरत है वह है अपने HTML में एक कंटेनर जोड़ना
<div class="container" id="pjax-container"> Go to <a href="/page/2">next page</a>. </div>
अब मुझे PJAX लिंक सेट अप करने की आवश्यकता है:
$(document).pjax('a', '#pjax-container')
अंत में, मैं रेल्स को PJAX अनुरोधों पर लेआउट रेंडर न करने के लिए कहूंगा। आपको ऐसा कुछ करना होगा, या आप डुप्लिकेट हेडर और फुटर के साथ समाप्त होंगे। यानी आपकी वेबसाइट इनसेप्शन की तरह दिखेगी।
def index if request.headers['X-PJAX'] render :layout => false end end
यह इतना आसान नहीं है!
ठीक है, यह मेरे द्वारा बताए गए से थोड़ा अधिक जटिल है। ज्यादातर एक विशाल गड्ढे के कारण जिसके बारे में बहुत कम लोग बात करते हैं।
जब आपका DOM हर पेज लोड पर क्लियर नहीं होता, तो इसका मतलब है कि JS जो आपके पारंपरिक रेल्स ऐप पर काम कर सकता था अब बहुत अजीब तरीकों से टूट जाता है।
इसका कारण यह है कि हम में से कई लोगों ने JS लिखना सीखा है जो आकस्मिक नामकरण संघर्ष को प्रोत्साहित करता है। सबसे कपटी दोषियों में से एक साधारण jQuery सेलेक्टर है।
// I may look innocent, but I'm not! $(".something")
पेज के लिए JS लिखना जो रीलोड नहीं होते
संघर्ष नंबर एक समस्या है जब आप उन पेज के लिए JS लिखते हैं जो कभी रीलोड नहीं होते। कुछ सबसे अजीब, डीबग करना कठिन समस्याएं तब होती हैं जब JS उस HTML में हेरफेर करता है जिसे छूने के लिए उसका कभी मतलब नहीं था। उदाहरण के लिए, आइए एक सामान्य jQuery इवेंट हैंडलर देखें:
$(document).on("click", ".hide-form", function() { $(".the-form").hide(); });
यह पूरी तरह से उचित है, अगर यह केवल एक पेज पर चलता है। लेकिन अगर DOM कभी रीलोड नहीं होता, तो यह केवल समय की बात है जब तक कोई साथ आता है और .hide-form क्लास के साथ एक और तत्व जोड़ता है। अब आपके पास एक संघर्ष है।
इस तरह के संघर्ष तब होते हैं जब आपके पास बहुत सारे ग्लोबल रेफरेंस होते हैं। और आप ग्लोबल रेफरेंस की संख्या कैसे कम करते हैं? आप नेमस्पेस का उपयोग करते हैं।
सेलेक्टर्स को नेमस्पेस करना
नीचे दी गई रूबी क्लास में, हम एक ग्लोबल नाम - क्लास नाम - का उपयोग करके बहुत सारे मेथड नाम छिपा रहे हैं।
# One global name hides two method names class MyClass def method1 end def method2 end end
जबकि DOM तत्वों को नेमस्पेस करने के लिए कोई बिल्ट-इन समर्थन नहीं है (कम से कम ES6 वेबकंपोनेंट्स आने तक नहीं) कोडिंग कन्वेंशन के साथ नेमस्पेस का अनुकरण करना संभव है।
उदाहरण के लिए, कल्पना करें कि आप एक टैग एडिटिंग विजेट लागू करना चाहते थे। नेमस्पेस के बिना, यह कुछ इस तरह दिख सकता है। ध्यान दें कि तीन ग्लोबल रेफरेंस हैं।
// <input class="tags" type="text" /> // <button class="tag-submit">Save</button> // <span class="tag-status"></span> $(".tag-submit").click(function(){ save($(".tags").val()); $(".tag-status").html("Tags were saved"); });
हालांकि, एक "नेमस्पेस" बनाकर और सभी तत्व लुकअप को इसके सापेक्ष बनाकर, हम ग्लोबल रेफरेंस की संख्या को एक तक कम कर सकते हैं। हम कई क्लास से पूरी तरह छुटकारा भी पा चुके हैं।
// <div class="tags-component"> // <input type="text" /> // <button>Save</button> // <span></span> // </div> $container = $("#tags-component") $container.on("click", "button" function(){ save($container.find("input").val()); $container.find("span").html("Tags were saved"); });
मैंने कहा था कि यह सरल है।
उपरोक्त उदाहरण में, मैंने अपने DOM तत्वों को "tags-component" क्लास वाले कंटेनर के अंदर रखकर नेमस्पेस किया। उस विशेष नाम के बारे में कुछ खास नहीं है। लेकिन अगर मैं एक नामकरण कन्वेंशन अपनाता जहां हर नेमस्पेस कंटेनर की क्लास "-component" पर समाप्त होती है तो कुछ बहुत दिलचस्प चीजें होती हैं।
आप गलत ग्लोबल सेलेक्टर्स को एक नज़र में पहचान सकते हैं।
यदि आप केवल घटकों के लिए ग्लोबल सेलेक्टर्स की अनुमति देते हैं, और सभी घटकों की क्लास "-component" पर समाप्त होती है तो आप एक नज़र में देख सकते हैं कि क्या आपके पास कोई खराब ग्लोबल सेलेक्टर्स हैं।
// Bad $(".foo").blah() // Ok $(".foo-component".blah()
उस HTML को नियंत्रित करने वाले JS को ढूंढना आसान हो जाता है
आइए हमारे इंटरैक्टिव टैग फॉर्म को फिर से देखें। आपने फॉर्म के लिए HTML लिखा है। अब आपको कुछ JS और CSS जोड़ने की आवश्यकता है। लेकिन आप उन फाइलों को कहां रखते हैं? सौभाग्य से, जब आपके पास नेमस्पेस के लिए एक नामकरण योजना होती है, तो यह आसानी से JS और CSS फाइलों के लिए नामकरण योजना में तब्दील हो जाती है। यहाँ डायरेक्टरी ट्री कैसा दिख सकता है।
. ├── javascripts | ├── application.coffee │ └── components │ └── tags.coffee └── stylesheets ├── application.scss └── components └── tags.scss
स्वचालित आरंभीकरण
एक पारंपरिक वेब ऐप में, पेज लोड पर अपने सभी JS को इनिशियलाइज़ करना सामान्य है। लेकिन PJAX और टर्बोलिंक्स के साथ, तत्वों को हर समय DOM में जोड़ा और हटाया जाता है। इस वजह से, यह वास्तव में फायदेमंद है अगर आपका कोड स्वचालित रूप से पता लगा सकता है कि नए घटक कब DOM में प्रवेश करते हैं, और उनके लिए जो भी JS आवश्यक है उसे ऑन-द-फ्लाई इनिशियलाइज़ करें।
एक सुसंगत नामकरण योजना, इसे करना वास्तव में आसान बनाती है। ऑटो-इनिशियलाइज़ेशन के लिए आप अनगिनत दृष्टिकोण अपना सकते हैं। यहाँ एक है:
Initializers = { tags: function(el){ $(el).on("click", "button", function(){ // setup component }); } // Other initializers can go here } // Handler called on every normal and pjax page load $(document).on("load, pjax:load", function(){ for(var key in Initializers){ $("." + key + "-component").each(Initializers[key]); } }
यह आपके CSS को भी बेहतर बनाता है!
JavaScript वेब पेज पर संघर्ष का एकमात्र स्रोत नहीं है। CSS और भी बदतर हो सकता है! सौभाग्य से, हमारी चतुर नेमस्पेसिंग प्रणाली CSS को संघर्ष के बिना लिखना भी बहुत आसान बनाती है। यह SCSS में और भी अच्छा है:
.tags-component { input { ... } button { ... } span { ... } }