जावास्क्रिप्ट में इवल के लिए एक अच्छा मामला
या: लिट-एचटीएमएल टेम्पलेट्स के अंदर गतिशील एचटीएमएल टैग कैसे उत्पन्न करें? eval
कभी-कभी मिलाया जाता है evil
। हम कभी-कभी यह भी सुनते हैं कि ऐसे मामले हैं जिनमें इसकी आवश्यकता होती है। ऐसा ही एक मामला है...
परियोजना वेब घटकों के lit
साथ काम करने के लिए एक रूपरेखा है। स्पष्ट रूप से 1.x और 2.x में हम पर बहुत अधिक निर्भर थे lit
। जबकि हम विशद 3.x पर कड़ी मेहनत कर रहे हैं, हम अभी भी समर्थन करते हैं और इसमें सुविधाएँ जोड़ते हैं 2.x
।
ऐसी ही एक विशेषता विस्तार पैनल घटक के चारों ओर एक एच टैग जोड़ना था। क्योंकि विस्तार पैनल का उपयोग हेडर के रूप में किया जा सकता है (और ज्यादातर वे करते हैं), हमें उन्हें हेडर के रूप में शब्दार्थ रूप से सेट करने की आवश्यकता है।
हमने तय किया है कि डिफ़ॉल्ट एच स्तर 3 ( <h3>
) होगा। यह पर्याप्त नहीं है क्योंकि विस्तार पैनल किसी अन्य शीर्षलेख स्तर का उप शीर्षलेख भी हो सकता है:
<h1>Is there alien life out there?</h1>
<expansion-panel>
<h2><button>What is life?</button></h2>
</expansion-panel>
<expansion-panel>
<h2><button>What is alien?</button></h2>
</expansion-panel>
div
कुछ लोग a और का उपयोग करने aria-level
के लिए कहेंगे role=header
। हालांकि यह काम करता, एमडीएन (और अन्य स्थानों) से यह उद्धरण है:
इन सब बातों को ध्यान में रखते हुए, हम डायनामिक टैग की अनुमति देते हुए MDN के सर्वोत्तम अभ्यासों को बनाए रखना चाहते थे।
lit-html के साथ एक डायनामिक टैग सेटअप करने का प्रयास कर रहा है
जले हुए टेम्पलेट कैसे काम करते हैं?
आइए पहले समझाएं कि lit
विवरण में बहुत अधिक जानकारी प्राप्त किए बिना टेम्प्लेटिंग कैसे काम करता है।
lit-html
एक उपयोगिता फ़ंक्शन है जो हमारे स्ट्रिंग्स को लाइव टेम्प्लेट में बदल देता है। रेंडर विधि तब lit
"जादुई रूप से" टेम्पलेट में गुणों में परिवर्तन को सुनती है और तदनुसार दृश्य को अपडेट करती है।
तो आपके पास एक ऐसा render
फ़ंक्शन होगा जो इस तरह दिखता है:
पैनल हेडर वह सामग्री होगी जिसे हम हेडर के रूप में नामित करना चाहते हैं।
जैसा कि मैंने उल्लेख किया है, हम इसे डिफ़ॉल्ट रूप से लपेटना चाहते थे h3
, इसलिए यह कुछ इस तरह दिख सकता है:
लिट-एचटीएमएल में टैग नाम को गतिशील रूप से कैसे नहीं बदला जाए?
दूसरी आवश्यकता h tag
गतिशील होने की थी। इसका मतलब है, हम एक उपयोगकर्ता संपादन योग्य संपत्ति चाहते हैं जो हेडर के स्तर को बदल दे। टेम्प्लेट को देखते हुए, यह एक आसान काम लग सकता है। बस टेम्पलेट स्ट्रिंग के अंदर चर सेट करें h
:
कितना बढ़िया लग रहा है! और यह कितनी शानदार ढंग से विफल रहता है :)
आप देखते हैं - lit-html
और टेम्प्लेटिंग सिस्टम स्थिर डेटा के साथ अच्छी तरह से काम नहीं करता है। मैं आपको खौफनाक विवरण नहीं दूंगा, लेकिन हमें जो त्रुटि मिलती है वह यह है कि यह टेम्पलेट को पार्स करने में विफल रहता है - और यह रनटाइम में होता है! (आउच - कल्पना कीजिए कि अगर हमारे पास परीक्षण नहीं होते तो क्या होता)
उपयोग करने की कोशिश कर रहा हैunsafeHTML
आप जानते हैं कि वे क्या कहते हैं: "यदि आप उनसे नहीं लड़ सकते - उनके तरीकों का उपयोग करें"। unsafeHTML
निम्नलिखित करने के वादे नामक एक प्रकाशित विधि : Renders the result as HTML, rather than text.
चूंकि दस्तावेज़ीकरण की कमी थी, इसलिए मैंने आधिकारिक दस्तावेज़ीकरण की ओर रुख किया - इकाई परीक्षण:
इसे हमारे कोड पर लागू करना इस तरह दिखता है:
ठीक है - बिल्ड पास हो गया। परीक्षण विफल (लेकिन परीक्षण कौन देखता है, है ना?) वे असफल क्यों हुए? इस समाधान का उपयोग करते समय यह कैसा दिखता है:
मैं विवरण में नहीं जाऊंगा कि यह काम क्यों नहीं करता - यह कहने के लिए पर्याप्त है कि जिस तरह से lit-html
इसके टेम्पलेट्स को प्रस्तुत किया जाता है वह "ढीले" एचटीएमएल टैग समाप्त होने की अनुमति नहीं देता है।
हम शून्य बिंदु पर वापस आ गए हैं। हमने कुछ ऐसा करने की कोशिश की जो काम नहीं कर रहा था... आगे बढ़ने का समय!
unsafe
स्टेटिक . का उपयोग करने की कोशिश कर रहा है
हमारा तीसरा प्रयास कॉल के दूसरे बिल्ट इन फंक्शन का उपयोग करना lit
था unsafeStatic
। फिर से प्रलेखन बहुत उपयोगी नहीं है, इसलिए... आप जानते हैं... इकाई परीक्षण:
लगता है हमारी समस्या का समाधान हो गया है। आइए इसे हमारे कोड में लागू करें:
और फिर... हमें यह मिलता है:
जाहिर है, जबकि उनके परीक्षणों ने unit-tests
रेंडर के साथ काम किया, यह "वास्तविक दुनिया" में काम नहीं किया। अपने दम पर दौड़ना render
मुझे ठीक वैसा ही दिखा।
तो... unsafeStatic
काम नहीं करता। आगे क्या होगा?
Eval
लिट-एचटीएमएल टेम्प्लेट में डायनेमिक टैग जेनरेट करने के लिए कैसे उपयोग करें
हमारे पूर्व असफल प्रयास में हमने headerLevel
गतिशील रूप से इस तरह जोड़ने की कोशिश की:
<h${this.headerLevel}>
${this.renderPanelHeader()}
</h${this.headerLevel}>
हमारा समाधान अब हमारे हेडर के लिए एक डायनामिक टैग नाम के साथ एक डायनामिक टेम्प्लेट लौटाता है:
आइए इसे पूरी तरह से बंडल करें
ऐसा लगता है कि हम जो चाहते थे उसमें सफल हो गए। हमारे अंदर एक गतिशील टैग है lit-html
- और हमने इसका इस्तेमाल भी किया eval
...
हमें एक और "छोटा" मुद्दा मिला। हमारे ui दृश्य प्रतिगमन परीक्षण (वेबपैक द्वारा बंडल किए जा रहे हैं) चलाते समय हमें निम्नलिखित त्रुटि मिली:
वही त्रुटि हमारी स्टोरीबुक (वेबपैक, फिर से…) में दिखाई दी।
धत्तेरे की! अब हमारे घटक बंडल किए गए अनुप्रयोगों में उपयोग करने योग्य नहीं हैं (जो इस तरह हैं … 99% अनुप्रयोग विविड का उपभोग करते हैं)।
क्या करें? क्या करें? मुझे पता है - चलो उदास हो जाओ और हार मान लो!
या ... हम एक और बुरा समाधान लेकर आ सकते हैं!
यदि हम केवल स्थानीय चर के html
रूप में सेट करते हैं और स्थानीय चर का उपयोग करते हैं, तो यह रनटाइम में उपलब्ध होना चाहिए।
const safeHTML = html;
तो फ़ाइल के शीर्ष पर जोड़ने और फिर safeHTML
इसके बजाय उपयोग करने से html
हमारी समस्या हल हो जाती है।
वास्तव में - एक चर समस्याग्रस्त हो सकता है क्योंकि एक कुरूप/मिनिफायर इसे बदल सकता है। हम यह सुनिश्चित करने के लिए कक्षा में एक स्थिर विधि का उपयोग कर सकते हैं कि यह अधिक लचीला है। यह निर्भर करता है कि आपका कुरूप/मिनीफायर कितना "आक्रामक" है ...
फिलहाल मेरी समस्या नहीं है :)
सारांश
पहुंच एक महत्वपूर्ण मामला है। हम किसी को पीछे नहीं छोड़ना चाहते हैं, और यह सुनिश्चित करते हैं कि हमारे ऐप्स अधिक से अधिक लोगों तक पहुंच सकें।
अपने एचटीएमएल में सही सेमेन्टिक्स का इस्तेमाल करना इसका एक बड़ा हिस्सा है। यही कारण है कि vivid
टीम हमारे डिजाइन सिस्टम के घटकों में एक्सेसिबिलिटी सुविधाओं को जोड़ने पर लगातार काम कर रही है।
हमारे मामले में हम यह सुनिश्चित करना चाहते थे कि expansion panels
हेडर के रूप में सही शब्दार्थ प्राप्त करें। चूंकि हम उपभोक्ताओं को हेडर के स्तर को निर्धारित करने की अनुमति देना चाहते थे, हम चाहते थे कि h
टैग गतिशील हो।
lit-html
इसके साथ वास्तव में अच्छा नहीं था, इसलिए ऐसा करने के कुछ तरीकों को आजमाने के बाद, हमने पाया कि इसका उपयोग करके eval
हम अंदर एक गतिशील टैग बना सकते हैं lit-html
।
फिर हमें एक और छोटी समस्या मिली: जब हमारे घटक को अन्य ऐप्स (हमारे मामले में, ui विज़ुअल रिग्रेशन टेस्ट और स्टोरीबुक) के अंदर बंडल किया गया, तो हमने पाया कि उपयोग eval
करना मुश्किल है। यह आयातित नहीं मिलेगा html
क्योंकि eval
अभिव्यक्ति का मूल्यांकन रनटाइम में किया जाता है और बंडलर आयात को अपना नाम देते हैं ...
हमने कक्षा में स्थानीय संपत्ति बनाकर इसे हल किया और इसने चाल चली। हमारे पास एक डायनामिक टैग था जो बंडलर के साथ भी काम कर रहा था।
ऑपरेशन सफल रहा।
इस लेख की प्रेरणा और समीक्षा के लिए राहेल बी तन्ननबाम और यिनोन ओवेड को बहुत-बहुत धन्यवाद ।