AngularJS: `टेम्प्लेट 'बनाम' टेम्प्लेट '

पिछले कुछ महीनों में, मैं डोमो पर काम करने वाले विशाल एसपीए पर रनटाइम प्रदर्शन को बेहतर बनाने के विभिन्न तरीकों पर गौर कर रहा हूं। हमने कुछ गंभीर प्रगति की है, लेकिन एक एसपीए में एक लाख लाइनों के साथ, कुछ बदलाव हमेशा आसान नहीं होते हैं। हमारी टीम के सदस्यों में से एक ने AngularJS परियोजनाओं में आलसीपन को जोड़ने में मदद करने के लिए खोज की, और हमने इसमें भारी निवेश किया है। कुछ अलग टीम के सदस्य (जेसन और टिम) हमें उस समय को मापने में मदद करते हैं जो हमारे ऐप को पूरी तरह से शुरू करने में लेता है। हमने बिल्ड को सुव्यवस्थित करने के लिए वेबपैक का भी उपयोग किया है, साथ ही कुछ पैटर्न को भी बदलते हैं जिनका हम उपयोग करते हैं। ओक्लाजलोड के साथ वेबपैक का संयोजन करते समय, हमने एंगुलरजेएस परियोजनाओं के लिए एक गंभीर जीत पाई है।

पिछले सप्ताह, मैंने सभी घटक / निर्देशकीय टेम्पलेट घोषणाओं को बदलने का काम किया, और उन्हें templateUrl से टेम्पलेट में बदल दिया। मैन्युअल रूप से सभी टेम्प्लेटों को उनके अलग-अलग .html फाइलों को उनके संबंधित जेएस फाइलों में स्थानांतरित करने के बजाय, हमने वेबपैक लोडर का उपयोग करने का निर्णय लिया, और इनलाइन स्ट्रिंग्स के रूप में टेम्प्लेट की आवश्यकता होती है। इसे बेहतर ढंग से समझाने के लिए ... मैं आपको दिखाता हूं कि मेरा क्या मतलब है। निम्नलिखित एक नमूना AngularJS घटक है:

जैसा कि आप देख सकते हैं, पहले उदाहरण में, एक घटक है जो इसे टेम्पलेट को लोड करने के लिए टेम्प्लेट का उपयोग करता है। यह सबसे अच्छा समस्याग्रस्त है, IMO। इसका अर्थ है कि आपको उत्पादन करने के लिए foo / bar / myComponent.html फ़ाइल को तैनात करना होगा ताकि आपका उत्पादन ऐप इसे प्राप्त करने के लिए दूसरे नेटवर्क अनुरोध के माध्यम से टेम्पलेट के टुकड़े को लोड कर सके, या इसका मतलब है कि आपको एक बिल्ड जोड़ने की आवश्यकता होगी वह चरण जो सभी टेम्पलेट के उदाहरणों को खोजेगा और उन टेम्प्लेट्स को AngularJS टेम्प्लेट कैश में लाएगा। इन दोनों समाधानों में समस्याएं हैं।

पहली के साथ समस्याएं स्पष्ट हैं: यदि उत्पादन में आपके सभी टेम्पलेट्स को प्राप्त करने के लिए अलग नेटवर्क अनुरोध की आवश्यकता होती है, तो किसी एक दृश्य को लोड करने के लिए सभी विचारों को प्राप्त करने के लिए एन नेटवर्क अनुरोधों की आवश्यकता होगी, जहां एन घटकों की संख्या है / आपके विचार में निर्देश / ngIncludes।

दूसरे के साथ समस्या यह है कि सुपर आसान होते हुए बिल्ड चरण आपके सभी टेम्पलेट्स को आपके मुख्य वेबपैक बंडल में लोड कर देंगे। इसका मतलब यह है कि जब आप किसी घटक, या घटकों के एक पूरे अनुभाग को आलसी लोड करने का इरादा रखते हैं, तब भी उनके टेम्पलेट आपके छोटे बंडल के साथ लोड किए जाएंगे। इसलिए, आप उन लाभों का पूरा लाभ नहीं उठा सकते हैं जो आपको आलसी हो चुके हैं।

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

लाभ

सभी .html फ़ाइलों को लोड करने के लिए वेबपैक html-लोडर का उपयोग करके, हमने पाया कि हम अपने टेम्पलेट्स को कुशलतापूर्वक लोड करने में सक्षम थे, जबकि हमें आलसी लोडिंग का पूरी तरह से लाभ उठाने की अनुमति भी थी। जब आप टेम्पलेट का उपयोग करते हैं: आवश्यकता होती है ('foo / bar / my.html') सिंटैक्स, वेबपैक आपके आवश्यकता विवरण को एक फ़ंक्शन के साथ बदलता है जिसे कॉल किया जाता है और टेम्पलेट के लिए स्ट्रिंग के साथ वापस आ जाता है। चूंकि टेम्पलेट अब html स्ट्रिंग के रूप में प्रदान किया गया है, यदि आप घटक को आलसी लोड करते हैं, तो टेम्पलेट भी आलसी हो जाएगा। यह वही है जो हमें चाहिए था। हालांकि, हमने कई अन्य लाभों की खोज की, जिनमें से खोज ने इस पोस्ट को प्रेरित किया।

  • तेज़ घटक इनिशियलाइज़ेशन - जब आप टेम्पलेट के रूप में इनलाइन स्ट्रिंग का उपयोग करते हैं, तो घटक सिंक्रोनाइज़ कर सकता है। TemplateUrl का उपयोग करके, AngularJS टेम्पलेट से टेम्पलेट का अनुरोध करेगा। चूंकि टेम्प्लेट कैश में पहले से ही टेम्पलेट हो सकता है, या इसे प्राप्त करने के लिए नेटवर्क पर जाने की आवश्यकता हो सकती है, इसलिए कैश से टेम्पलेट का अनुरोध करना एक प्रक्रिया है जो अतुल्यकालिक रूप से होती है। भले ही टेम्प्लेट कैश में पहले से है, टेम्प्लेट कैश वादा किए गए कॉल के माध्यम से पहले से कैश किए गए टेम्प्लेट को वापस कर देगा। इसका मतलब यह है कि घटक एक ही घटना लूप में इनिशियलाइज़ नहीं कर सकता है। टेम्प्लेट कैश का अनुरोध हमेशा अगले ईवेंट लूप पर रखा जाएगा, यहां तक ​​कि सबसे अच्छे परिदृश्यों में भी। इसका मतलब है कि घटक आरंभ करना शुरू कर सकता है, इसके खाके का अनुरोध कर सकता है, और फिर अगले ईवेंट लूप में प्रारंभिक करना समाप्त कर सकता है। लेकिन जब आप इनलाइन स्ट्रिंग का उपयोग करते हैं, तो घटक में पहले से ही इसका खाका तैयार होता है, इसलिए यह उसी ईवेंट लूप में इसे शुरू और समाप्त कर सकता है। यह महत्वपूर्ण नहीं लग सकता है, लेकिन इसके कई अप्रत्याशित परिणाम थे जिनकी हमें क्षतिपूर्ति करनी थी।
    - घटक तेजी से इनिशियलाइज़ करते हैं - जो भयानक लगता है, AIR? खैर, यह कमाल है। हालाँकि, इसका मतलब है कि आपके कुछ घटक जो हमेशा अपने इनपुट मूल्यों को परिभाषित करते हैं, जब उनका इनिशियलाइज़ ब्रेक हो सकता है, क्योंकि वे समान मूल्य अभी तक नहीं हो सकते हैं। अपरिभाषित इनपुट बाध्यकारी मूल्यों के कारण हमारे पास कई घटक ब्रेक थे। इनपुट मानों के अपडेट का पता लगाने के लिए हमें उन घटकों को $ घड़ी या $ onChanges का उपयोग करना था।
    - यूनिट टेस्ट अलग तरीके से चलेंगे - क्योंकि जब आप एक सिंक्रोनस टेस्ट बनाम एसिंक्रोनस टेस्ट कर रहे होते हैं तो लेखन परीक्षण बदल जाते हैं, इन घटकों के लिए परीक्षण निश्चित रूप से बदल सकता है। उदाहरण के लिए, मोचा में, यदि आपका परीक्षण एसिंक्स है, तो आप अपने परीक्षण में किए गए तरीके को इंजेक्ट करते हैं, और परीक्षण किए जाने के बाद इसे कॉल करते हैं। हमने पाया कि परीक्षण अब समकालिक रूप से प्रदर्शन कर रहे थे, जिसका अर्थ था कि इंजेक्शन लगाने की आवश्यकता अब आवश्यक नहीं थी। इसके अलावा, और यह स्वीकार करने के लिए शर्मनाक है, लेकिन हमारे पास ऐसे परीक्षण थे जो सिंक्रोनस में लिखे गए थे, हालांकि, टेम्प्लेट async होने के साथ, उन परीक्षणों को कभी पूरा नहीं किया गया। इसलिए, जब मैंने टेम्प्लेट इनलाइन में बदलाव किए, तो वे परीक्षण सफलतापूर्वक चलने लगे, और पास होने के बजाय, वे असफल हो रहे थे !!!! पहले मुझे लगा कि मैंने उन सभी परीक्षणों को तोड़ दिया है। लगभग 5 घंटे तक रुकने के बाद मुझे पता ही नहीं चला कि ये परीक्षण कभी नहीं हुए थे। इसलिए हमने वास्तव में अब परीक्षण कवरेज बढ़ा दिया है कि हम इनलाइन टेम्पलेट्स का उपयोग कर रहे हैं।
  • html-loader एक html minifier का उपयोग करता है - इस छोटे से तथ्य ने हमारे टेम्पलेट्स के आकार को तुरंत पूरे ऐप में 19% तक कम कर दिया है। यह बहुत उत्कृष्ट है, और वास्तव में कुछ ऐसा है जो हमें लंबे समय तक करना चाहिए था। यह टेम्पलेट्स को पार्स भी करता है, और हमें कुछ दर्जन टेम्पलेट ढूंढने में मदद करता है जिनके पास अमान्य HTML था। चीजें जैसे: वर्ग "ब्लाह", जहां = गायब था। या विशेषता = {{कुछ}}, जो इसके चारों ओर उद्धरण याद कर रहा है। एक बार जब मैंने उन को ठीक कर लिया, तो बिल्ड ने फिर से काम किया।
  • एनजी-शामिल अभी भी टूट गए थे - जबकि घटक टेम्पलेट अब काम कर रहे थे, एनजी-शामिल अब टूट गए थे। हमें उनके लिए कुछ लेकर आने की जरूरत थी। इसलिए हमने एक छोटा कस्टम लोडर बनाया, जो टेम्पलेट को टेम्प्लेट में लाएगा। हमारी आंतरिक प्रथाएं बताती हैं कि हम एनजी-इन का उपयोग नहीं करते हैं, लेकिन हमारे पास अभी भी बहुत सारे 3 + वर्ष पुराने कोड हैं जिनमें वे शामिल हैं। इसलिए, इस कमिट में सभी को रिफलेक्टर करने के बजाय, मैंने इस नए लोडर का उपयोग किया, और ऐप के प्रत्येक सेक्शन में गया, जिसमें एनजी-इन्क्लूड है और उस सेक्शन के लिए टेम्प्लेट लोड किया है, जैसे मैंने नीचे दिखाया है। इसका मतलब है कि इस नई प्रक्रिया में एनजी-इन का भी ध्यान रखा गया है।

JSCodeShift का उपयोग किया

मैं पूरी तरह से AngularJS ऐप्स के लिए वेबपैक का उपयोग करने की सलाह देता हूं, और अपने टेम्प्लेट इनलाइन को लाने के लिए html-लोडर का उपयोग कर रहा हूं, जिसका अर्थ है कि आपको अपने टेम्प्लेटउल इंस्टेंसेस को टेम्प्लेट इंस्टेंस में बदलना होगा। चूंकि वे सभी बहुत अलग दिखते हैं, मैंने फैसला किया कि यह JSCodeShift के लिए एक बहुत अच्छा उपयोग मामला था, फेसबुक की एक परियोजना जो आपको एएसटी को क्रॉल करने की अनुमति देती है, और प्रोग्रामेटिक रूप से आपके लिए सभी उदाहरणों को प्रतिस्थापित करती है। आप इसे फाइंड एंड रिप्लेस ऑन स्टेरॉयड, इंजेक्टेड डब्ल्यू / मोर स्टेरॉयड के रूप में सोच सकते हैं। स्क्रिप्ट को लिखने के लिए वास्तव में सरल था जो टेम्प्लेट के इन सभी उपयोगों को पाया और अपडेट किया गया था: / कुछ / url / to.html के साथ टेम्प्लेट: आवश्यकता ()। मैं 90% usages को प्रोग्रामेटिक रूप से (लगभग 700 फाइलें) बदलने में सक्षम था, और मुझे अंतिम 70 को हाथ से खत्म करना था। मैं उन अन्य 70 को खत्म करने के लिए कोड लिख सकता था, लेकिन मुझे लगा कि मैं व्यक्तिगत रूप से उन्हें कोड करने की कोशिश करके हाथ से आसान काम कर सकता हूं। एक त्वरित नोट, एएसटी एक्सप्लोरर JSCodeShift का उपयोग करते समय एक पूर्ण होना चाहिए। इसके बिना, मैं कोई प्रगति नहीं कर सकता।

निष्कर्ष

अपने AngularJS ऐप को वेबपैक बिल्ड पर प्राप्त करें, और अपने टेम्प्लेट लोड करने के लिए html-लोडर का उपयोग करने के लिए उन्हें प्राप्त करने के लिए समय दें। टेम्प्लेट यूआरएल के बजाय टेम्प्लेट का उपयोग करें, और यदि आप पहले से ही नहीं हैं, तो एनजी-इनका उपयोग करना बंद करें। और फिर, आलसी, आलसी, आलसी! कुछ बार लोग विलंबित लोडिंग और आलसी लोडिंग के बीच अंतर करते हैं। जब मुझे "आलसी लोड" कहते हैं, तो मैं लोडिंग और आलसी लोडिंग दोनों का उल्लेख कर रहा हूं। फर्स्ट सार्थक पेंट के लिए समय को कम करने और उपयोगकर्ता के साथ बातचीत कर सकने वाले ऐप को कम करने के लिए यह आपका सबसे अच्छा बदलाव है। सौभाग्य। वापस अपने सिर पर!