Turbolinks - यह शायद रेल ब्रह्मांड में सबसे तिरस्कृत शब्दों में से एक है।
हो सकता है कि आपने इसे आजमाया हो। आपने नए प्रोजेक्ट या किसी मौजूदा ऐप्लिकेशन में टर्बोलिंक शामिल किए हैं. और जल्द ही ऐप अजीब और अद्भुत तरीकों से विफल होने लगा। अच्छी बात है कि इसे ठीक करना उतना ही आसान था - टर्बोलिंक बंद करें।
...लेकिन कुछ कंपनियां इसे काम करती हैं। यहां हनीबैगर में, हमने इसे काम कर दिया है - और हम कोई जीनियस नहीं हैं।
इसका उत्तर इतना सरल है कि मैं इसे लाने में लगभग झिझक रहा हूं। लेकिन रूबी नेशन और मैडिसन+रूबी में इस विषय पर बातचीत करने के बाद, ऐसा लगता है कि लोगों को यह विषय मददगार लगता है। तो चलिए देखते हैं।
टर्बोलिंक और PJAX कैसे काम करते हैं
Turbolinks और PJAX अनिवार्य रूप से उसी तरह काम करते हैं। वे बहुत समान हैं, मैं अभी से केवल PJAX कहने जा रहा हूँ। :)पी>
आप PJAX को दो पेज अनुरोधों के संदर्भ में समझ सकते हैं। जब कोई उपयोगकर्ता पहली बार किसी पृष्ठ का अनुरोध करता है, तो उसे किसी अन्य "पारंपरिक" रेल पृष्ठ की तरह ही दिखाया जाता है। लेकिन जब उपयोगकर्ता पीजेएक्स-सक्षम लिंक पर क्लिक करता है, तो कुछ खास होता है। पृष्ठ को पूरी तरह से पुनः लोड करने के बजाय, पृष्ठ का केवल एक भाग अपडेट किया जाता है। यह AJAX के माध्यम से किया जाता है।
कुछ कठिनाइयों को दूर करते हुए यह हमें एक पेज के ऐप के बहुत सारे फायदे देता है:
- PJAX ऐप्स अक्सर सिंगल पेज ऐप्स की तरह ही तेज़ लगते हैं, क्योंकि पेज को अब हर अनुरोध पर पूरी तरह से पुनः लोड नहीं करना पड़ता है।
- फ्रंट-एंड और बैक-एंड डेवलपमेंट के लिए आप एक ही स्टैक का उपयोग कर सकते हैं
- PJAX ऐप्स डिफ़ॉल्ट रूप से इनायत से खराब हो जाते हैं जब उपयोगकर्ता ने JS को अक्षम कर दिया होता है
- PJAX ऐप्स को अधिक आसानी से सुलभ और SEO के अनुकूल बनाया गया है
टर्बोलिंक लागू करना
ऐसे कई पुस्तकालय हैं जो आपके लिए पीजेएक्स की भारी भारोत्तोलन करेंगे। Turbolinks शायद सबसे प्रसिद्ध है। इसे सेट अप करना केवल आपके Gemfile में टर्बोलिंक्स रत्न को शामिल करने का मामला है:
gem 'turbolinks'
...और ऐप्लिकेशन/संपत्ति/जावास्क्रिप्ट/application.js
में JS शामिल करें//= require turbolinks
अब जब आप अपना ऐप पुनः लोड करते हैं, तो प्रत्येक आंतरिक लिंक एक टर्बोलिंक होगा। जब आप उन पर क्लिक करते हैं, तो नए पेज के लिए AJAX के माध्यम से अनुरोध किया जाएगा और वर्तमान दस्तावेज़ में डाला जाएगा।
jquery-pjax लागू करना
यहां हनीबैगर में, हम एक पीजेएक्स लाइब्रेरी का उपयोग करते हैं जिसे मूल रूप से जीथब द्वारा विकसित किया गया था। इसे Turbolinks की तुलना में थोड़ा अधिक कॉन्फ़िगरेशन की आवश्यकता है, लेकिन यह थोड़ा अधिक लचीला भी है।
यह मानने के बजाय कि सभी लिंक PJAX हैं, यह आपको इसे नियंत्रित करने देता है। यह आपको यह भी नियंत्रित करने देता है कि पेज पर PJAX सामग्री कहाँ डाली जाएगी।
पहली चीज़ जो मुझे करने की ज़रूरत है वह है मेरे एचटीएमएल में एक कंटेनर जोड़ना
<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 जो आपके पारंपरिक रेल ऐप पर काम कर सकता था, अब बहुत ही अजीब तरीके से टूट जाता है।
इसका कारण यह है कि हम में से कई लोगों ने जेएस लिखना इस तरह से सीखा जिससे आकस्मिक नामकरण संघर्षों को बढ़ावा मिला। सबसे कपटी अपराधियों में से एक साधारण jQuery चयनकर्ता है।
// I may look innocent, but I'm not!
$(".something")
फिर से लोड नहीं होने वाले पेजों के लिए JS लिखना
जब आप उन पृष्ठों के लिए JS लिखते हैं जो कभी पुनः लोड नहीं होते हैं, तो संघर्ष नंबर एक समस्या है। कुछ अजीबोगरीब, कठिन डिबग समस्याएँ तब होती हैं जब JS HTML में हेरफेर करता है जिसे छूने के लिए कभी नहीं बनाया गया था। उदाहरण के लिए, आइए एक सामान्य jQuery ईवेंट हैंडलर को देखें:
$(document).on("click", ".hide-form", function() {
$(".the-form").hide();
});
यह पूरी तरह से उचित है, अगर यह केवल एक पृष्ठ पर चलता है। लेकिन अगर डोम कभी भी पुनः लोड नहीं होता है, तो किसी के साथ आने से पहले यह केवल समय की बात है और .hide-form की कक्षा के साथ एक और तत्व जोड़ता है। अब आपका विरोध है।
इस तरह के विरोध तब होते हैं जब आपके पास बहुत सारे वैश्विक संदर्भ होते हैं। और आप वैश्विक संदर्भों की संख्या को कैसे कम करते हैं? आप नाम स्थान का उपयोग करते हैं।
नेमस्पेसिंग चयनकर्ता
नीचे दिए गए रूबी वर्ग में, हम बहुत सारे मेथड नामों को छिपाने के लिए एक वैश्विक नाम - क्लास नाम - का उपयोग कर रहे हैं।
# One global name hides two method names
class MyClass
def method1
end
def method2
end
end
हालांकि DOM तत्वों को नाम स्थान देने के लिए कोई अंतर्निहित समर्थन नहीं है (कम से कम ES6 WebComponents आने तक) कोडिंग सम्मेलनों के साथ नाम स्थान का अनुकरण करना संभव है।
उदाहरण के लिए, मान लें कि आप एक टैग संपादन विजेट लागू करना चाहते हैं। नेमस्पेसिंग के बिना, यह कुछ इस तरह दिख सकता है। ध्यान दें कि तीन वैश्विक संदर्भ हैं।
// <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 तत्वों को "टैग-घटक" वर्ग के साथ एक कंटेनर के अंदर रखकर उनका नाम स्थान दिया है। उस विशेष नाम के बारे में कुछ खास नहीं है। लेकिन अगर मैं एक नामकरण परंपरा को अपनाना चाहता हूं जहां प्रत्येक नामस्थान कंटेनर में "-घटक" में समाप्त होने वाली कक्षा होती है तो कुछ बहुत ही रोचक चीजें होती हैं।
आप एक नज़र में गलत वैश्विक चयनकर्ताओं को पहचान सकते हैं।
यदि आप केवल वैश्विक चयनकर्ताओं को घटकों की अनुमति देते हैं, और सभी घटकों में "-घटक" में समाप्त होने वाला वर्ग है, तो आप एक नज़र में देख सकते हैं कि क्या आपके पास कोई खराब वैश्विक चयनकर्ता है।
// Bad
$(".foo").blah()
// Ok
$(".foo-component".blah()
HTML को नियंत्रित करने वाले JS को खोजना आसान हो जाता है
आइए हमारे इंटरेक्टिव टैग फॉर्म पर फिर से गौर करें। आपने फॉर्म के लिए HTML लिखा है। अब आपको कुछ JS और CSS जोड़ने की जरूरत है। लेकिन आप उन फाइलों को कहां रखते हैं? सौभाग्य से, जब आपके पास नेमस्पेस के लिए नामकरण योजना होती है, तो यह आसानी से जेएस और सीएसएस फाइलों के लिए नामकरण योजना में तब्दील हो जाती है। यहाँ निर्देशिका ट्री कैसा दिखाई दे सकता है।
.
├── javascripts
| ├── application.coffee
│ └── components
│ └── tags.coffee
└── stylesheets
├── application.scss
└── components
└── tags.scss
स्वचालित आरंभीकरण
एक पारंपरिक वेब ऐप में, अपने सभी JS को पेज लोड पर इनिशियलाइज़ करना सामान्य है। लेकिन PJAX और Turbolinks के साथ, आपके पास हर समय DOM से तत्वों को जोड़ा और हटाया जा रहा है। इस वजह से, यह वास्तव में फायदेमंद है यदि आपका कोड स्वचालित रूप से पता लगा सकता है जब नए घटक डोम में प्रवेश करते हैं, और जो कुछ भी जेएस की आवश्यकता होती है उसे शुरू करते हैं।
एक सुसंगत नामकरण योजना, इसे करना वास्तव में आसान बनाती है। ऐसे अनगिनत दृष्टिकोण हैं जिन्हें आप स्वतः आरंभीकरण के लिए अपना सकते हैं। ये रहा एक:
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 को भी बेहतर बनाता है!
जावास्क्रिप्ट वेब पेज पर विरोध का एकमात्र स्रोत नहीं है। सीएसएस और भी बुरा हो सकता है! सौभाग्य से, हमारा निफ्टी नेमस्पेसिंग सिस्टम बिना किसी विरोध के सीएसएस लिखना बहुत आसान बना देता है। यह SCSS में और भी अच्छा है:
.tags-component {
input { ... }
button { ... }
span { ... }
}