HTML' का नया टेंप्लेट टैग

क्लाइंट-साइड टेंप्लेट का स्टैंडर्ड तय करना

शुरुआती जानकारी

टेंप्लेट बनाने की अवधारणा वेब डेवलपमेंट के लिए नई नहीं है. असल में, Django (Python), ERB/Haml (Ruby), और Smarty (PHP) जैसी भाषा/इंजन का टेंप्लेट लंबे समय से इस्तेमाल किया जा रहा है. हालांकि, पिछले कुछ सालों में हमने एमवीसी फ़्रेमवर्क में बढ़ोतरी देखी है. ये सभी थोड़े अलग होते हैं, फिर भी उनमें प्रज़ेंटेशन लेयर (यानी 'डा व्यू)' को रेंडर करने के लिए एक ही तरीका मिलता है.

चलिए, इस मुश्किल को देखते हैं. टेंप्लेट शानदार हैं. आगे बढ़ें, आस-पास पूछें. यहां तक कि इसकी परिभाषा भी आपको गर्म और आरामदेह महसूस कराती है:

"...हर बार नया बनाने की ज़रूरत नहीं है..." आपके बारे में नहीं पता है, लेकिन मुझे ज़्यादा काम करने से बचना पसंद है. फिर वेब प्लैटफ़ॉर्म पर किसी ऐसी चीज़ के लिए स्थानीय सहायता की कमी क्यों है जो डेवलपर को साफ़ तौर पर पसंद है?

WhatWG HTML टेंप्लेट खास जानकारी, इस सवाल का जवाब है. यह एक नए <template> एलिमेंट के बारे में बताता है, जो क्लाइंट-साइड टेंप्लेट के लिए स्टैंडर्ड डीओएम पर आधारित तरीके के बारे में बताता है. टेंप्लेट की मदद से, मार्कअप के उन फ़्रैगमेंट का एलान किया जा सकता है जिन्हें एचटीएमएल के तौर पर पार्स किया गया है. साथ ही, पेज लोड होने के दौरान उनका इस्तेमाल नहीं किया जाता. हालांकि, बाद में रनटाइम के दौरान उन्हें इंस्टैंशिएट किया जा सकता है. राफ़ेल वेनस्टेन को कोट करने के लिए:

यहां पर एचटीएमएल के बड़े ढेर को किसी भी कारण से ब्राउज़र के साथ खराब होने से बचाना है.

राफ़ेल वेनस्टेन (खास जानकारी के लेखक)

सुविधा की पहचान करने वाली सुविधा

<template> का पता लगाने की सुविधा के लिए, डीओएम एलिमेंट बनाएं और देखें कि .content प्रॉपर्टी मौजूद है या नहीं:

function supportsTemplate() {
    return 'content' in document.createElement('template');
}

if (supportsTemplate()) {
    // Good to go!
} else {
    // Use old templating techniques or libraries.
}

टेंप्लेट के कॉन्टेंट का एलान करना

एचटीएमएल <template> एलिमेंट आपके मार्कअप में किसी टेंप्लेट को दिखाता है. इसमें "टेंप्लेट कॉन्टेंट" होता है. यह क्लोन किए जा सकने वाले डीओएम के इनर्ट हिस्से होता है. टेंप्लेट को इस तरह की चीज़ों के तौर पर देखें जिनका इस्तेमाल ऐप्लिकेशन के पूरे जीवनकाल के लिए किया जा सकता है (और उनका फिर से इस्तेमाल किया जा सकता है).

टेंप्लेट वाला कॉन्टेंट बनाने के लिए, कुछ मार्कअप का एलान करें और उसे <template> एलिमेंट में रैप करें:

<template id="mytemplate">
    <img src="" alt="great image">
    <div class="comment"></div>
</template>

पिलर

<template> में कॉन्टेंट को रैप करने से, हमें कुछ अहम प्रॉपर्टी मिलती हैं.

  1. इसका कॉन्टेंट तब तक इस्तेमाल नहीं किया जा सकता, जब तक इसे चालू नहीं किया जाता. आम तौर पर, आपका मार्कअप छिपा हुआ डीओएम होता है और यह रेंडर नहीं होता है.

  2. टेंप्लेट में मौजूद किसी भी कॉन्टेंट का खराब असर नहीं होगा. स्क्रिप्ट नहीं चलती, इमेज लोड नहीं होती हैं, ऑडियो नहीं चलता,...जब तक टेंप्लेट का इस्तेमाल न किया जाए.

  3. यह माना गया है कि कॉन्टेंट, दस्तावेज़ में मौजूद नहीं है. मुख्य पेज में document.getElementById() या querySelector() का इस्तेमाल करने से, टेंप्लेट के चाइल्ड नोड नहीं दिखेंगे.

  4. टेंप्लेट को <head>, <body> या <frameset> के अंदर कहीं भी रखा जा सकता है. साथ ही, इनमें ऐसी किसी भी तरह का कॉन्टेंट हो सकता है जिसे इन एलिमेंट में इस्तेमाल करने की अनुमति है. ध्यान दें कि "कहीं भी" का मतलब है कि <template> को ऐसी जगहों पर सुरक्षित तरीके से इस्तेमाल किया जा सकता है जहां एचटीएमएल पार्सर की अनुमति नहीं है...कॉन्टेंट मॉडल को छोड़कर, बाकी सभी. इसे <table> या <select> के बच्चे के तौर पर भी रखा जा सकता है:

<table>
  <tr>
    <template id="cells-to-repeat">
      <td>some content</td>
    </template>
  </tr>
</table>

टेंप्लेट चालू करना

किसी टेंप्लेट का इस्तेमाल करने के लिए, आपको उसे चालू करना होगा. ऐसा न करने पर, इसका कॉन्टेंट कभी रेंडर नहीं होगा. इसका सबसे आसान तरीका यह है कि document.importNode() का इस्तेमाल करके, इसके .content की डीप कॉपी बनाई जाए. .content प्रॉपर्टी, रीड-ओनली DocumentFragment है. इसमें टेंप्लेट के गेस मौजूद हैं.

var t = document.querySelector('#mytemplate');
// Populate the src at runtime.
t.content.querySelector('img').src = 'logo.png';

var clone = document.importNode(t.content, true);
document.body.appendChild(clone);

किसी टेंप्लेट पर स्टैंप लगाने के बाद, उसका कॉन्टेंट "लाइव हो जाता है". इस उदाहरण में, कॉन्टेंट की क्लोन बनाई गई है, इमेज के लिए अनुरोध किया गया है, और फ़ाइनल मार्कअप रेंडर किया गया है.

डेमो

उदाहरण: इनर्ट स्क्रिप्ट

इस उदाहरण में दिखाया गया है कि टेंप्लेट कॉन्टेंट कितने काम का है. <script> सिर्फ़ तब काम करता है, जब बटन को दबाया जाता है. इससे टेंप्लेट पर मोहर हट जाती है.

<button onclick="useIt()">Use me</button>
<div id="container"></div>
<script>
  function useIt() {
    var content = document.querySelector('template').content;
    // Update something in the template DOM.
    var span = content.querySelector('span');
    span.textContent = parseInt(span.textContent) + 1;
    document.querySelector('#container').appendChild(
      document.importNode(content, true)
    );
  }
</script>

<template>
  <div>Template used: <span>0</span></div>
  <script>alert('Thanks!')</script>
</template>

उदाहरण: टेंप्लेट से शैडो डीओएम बनाना

ज़्यादातर लोग .innerHTML पर मार्कअप की स्ट्रिंग सेट करके, होस्ट में शैडो DOM अटैच करते हैं:

<div id="host"></div>
<script>
  var shadow = document.querySelector('#host').createShadowRoot();
  shadow.innerHTML = '<span>Host node</span>';
</script>

इस तरीके में समस्या यह है कि आपका Shadow DOM जितना जटिल होगा आप उतनी ही ज़्यादा स्ट्रिंग को जोड़ने की प्रोसेस करेंगे. यह बढ़ता नहीं है, चीज़ें तेज़ी से बिगड़ जाती हैं, और बच्चे रोने लगते हैं. इसी तरीके से XSS की शुरुआत शुरू में कैसे हुई! <template> को बचाने के लिए.

शैडो रूट में टेंप्लेट का कॉन्टेंट जोड़कर सीधे डीओएम के साथ काम करना फ़ायदेमंद होगा:

<template>
<style>
  :host {
    background: #f8f8f8;
    padding: 10px;
    transition: all 400ms ease-in-out;
    box-sizing: border-box;
    border-radius: 5px;
    width: 450px;
    max-width: 100%;
  }
  :host(:hover) {
    background: #ccc;
  }
  div {
    position: relative;
  }
  header {
    padding: 5px;
    border-bottom: 1px solid #aaa;
  }
  h3 {
    margin: 0 !important;
  }
  textarea {
    font-family: inherit;
    width: 100%;
    height: 100px;
    box-sizing: border-box;
    border: 1px solid #aaa;
  }
  footer {
    position: absolute;
    bottom: 10px;
    right: 5px;
  }
</style>
<div>
  <header>
    <h3>Add a Comment
  </header>
  <content select="p"></content>
  <textarea></textarea>
  <footer>
    <button>Post</button>
  </footer>
</div>
</template>

<div id="host">
  <p>Instructions go here</p>
</div>

<script>
  var shadow = document.querySelector('#host').createShadowRoot();
  shadow.appendChild(document.querySelector('template').content);
</script>

गॉचास

<template> को जंगल में इस्तेमाल करते समय, मुझे ये चीज़ें मिली हैं:

  • अगर modpagespeed का इस्तेमाल किया जा रहा है, तो इस गड़बड़ी से सावधान रहें. इनलाइन <style scoped> को परिभाषित करने वाले टेंप्लेट, इनमें से कई टेंप्लेट को PageSpeed के सीएसएस रीराइटिंग नियमों की मदद से लागू किया जा सकता है.
  • टेंप्लेट को "प्रीरेंडर" करने का कोई तरीका नहीं है. इसका मतलब है कि आपके पास एसेट को पहले से लोड करने, JS को प्रोसेस करने, शुरुआती सीएसएस को डाउनलोड करने वगैरह की सुविधा नहीं है. यह सर्वर और क्लाइंट, दोनों पर लागू होता है. टेंप्लेट के लाइव होने पर ही वह रेंडर होता है.
  • नेस्ट किए गए टेंप्लेट में सावधानी बरतें. वे आपकी उम्मीद के मुताबिक व्यवहार नहीं करते. उदाहरण के लिए:

    <template>
      <ul>
        <template>
          <li>Stuff</li>
        </template>
      </ul>
    </template>
    

    आउटर टेंप्लेट को चालू करने पर, इनर टेंप्लेट चालू नहीं होंगे. इसका मतलब है कि नेस्ट किए गए टेंप्लेट के लिए यह ज़रूरी है कि उनके बच्चे मैन्युअल तौर पर भी ऐक्टिव हों.

स्टैंडर्ड रास्ते पर ले जाने वाली सड़क

भूलना नहीं होगा कि हम कहां से आए थे. स्टैंडर्ड-आधारित एचटीएमएल टेंप्लेट पर काम करने का रास्ता लंबा रहा है. पिछले कुछ सालों में, हमने फिर से इस्तेमाल किए जा सकने वाले टेंप्लेट बनाने की कुछ बेहतरीन तरकीबें निकाली हैं. नीचे दो सामान्य सवाल दिए गए हैं. मैंने तुलना के लिए उन्हें इस लेख में शामिल किया है.

पहला तरीका: ऑफ़स्क्रीन DOM

लोग लंबे समय से "ऑफ़स्क्रीन" DOM बना सकते हैं और उसे दिखाने के लिए, hidden एट्रिब्यूट या display:none का इस्तेमाल कर सकते हैं. इसके लिए, एक तरीका इस्तेमाल कर रहे हैं.

<div id="mytemplate" hidden>
  <img src="logo.png">
  <div class="comment"></div>
</div>

हालांकि, यह तकनीक काम करती है, लेकिन इसमें कई समस्याएं हैं. इस तकनीक का रनडाउन:

  • DOM का इस्तेमाल करना - ब्राउज़र को DOM के बारे में पता है. यह इस में अच्छी है. हम आसानी से इसका क्लोन बना सकते हैं.
  • कुछ भी रेंडर नहीं किया गया - hidden जोड़ने से ब्लॉक दिखना बंद हो जाता है.
  • इनऐक्टिव नहीं है - भले ही, हमारा कॉन्टेंट छिपा हुआ हो, फिर भी इमेज के लिए नेटवर्क अनुरोध किया जाता है.
  • ध्यान खींचने वाली स्टाइल और थीम - एम्बेड किए गए पेज पर, उसके सभी सीएसएस नियमों के पहले #mytemplate होना चाहिए, ताकि स्टाइल को टेंप्लेट तक सीमित किया जा सके. यह प्रक्रिया बहुत ही नाज़ुक है और इस बात की कोई गारंटी नहीं है कि आने वाले समय में नाम में टकराव नहीं होगा. उदाहरण के लिए, अगर एम्बेड किए जाने वाले पेज में उस आईडी के साथ पहले से ही कोई एलिमेंट मौजूद है, तो हम हो जाते हैं.

दूसरा तरीका: स्क्रिप्ट को ओवरलोड करना

एक और तकनीक है, <script> को ओवरलोड और स्ट्रिंग के तौर पर इसके कॉन्टेंट में बदलाव करना. जॉन रेसिग ने शायद 2008 में अपनी माइक्रो टेंपलेटिंग यूटिलिटी के ज़रिए इसे पहली बार दिखाया था. अब और भी बहुत से बच्चे हैं. इनमें handlebars.js जैसे ब्लॉक पर नए बच्चे भी शामिल हैं.

उदाहरण के लिए:

<script id="mytemplate" type="text/x-handlebars-template">
  <img src="logo.png">
  <div class="comment"></div>
</script>

इस तकनीक का रनडाउन:

  • कुछ भी रेंडर नहीं किया गया - ब्राउज़र इस ब्लॉक को रेंडर नहीं करता, क्योंकि <script> डिफ़ॉल्ट रूप से display:none है.
  • Inert - ब्राउज़र, स्क्रिप्ट के कॉन्टेंट को JS के तौर पर पार्स नहीं करता क्योंकि इसका टाइप "text/javascript" के बजाय किसी और पर सेट होता है.
  • सुरक्षा से जुड़ी समस्याएं - यह .innerHTML का इस्तेमाल करने के लिए बढ़ावा देता है. उपयोगकर्ता से मिले डेटा की रन-टाइम स्ट्रिंग पार्स करने से, XSS के जोखिम की आशंका आसानी से पैदा हो सकती है.

नतीजा

याद है कि jQuery ने DOM के साथ काम करना आसान बना दिया? इसका नतीजा यह हुआ कि प्लैटफ़ॉर्म में querySelector()/querySelectorAll() को जोड़ा गया. जीत तो साफ़ तौर पर दिख रही है, है न? एक लाइब्रेरी ने फ़ेच करने वाले DOM को सीएसएस सिलेक्टर और स्टैंडर्ड के साथ बाद में अपनाया. यह हमेशा उस तरीके से काम नहीं करता, लेकिन मुझे यह पसंद है.

मुझे लगता है कि <template> भी ऐसा ही है. यह क्लाइंट-साइड टेंप्लेट बनाने के हमारे तरीके को स्टैंडर्ड करता है. हालांकि, इससे ज़्यादा अहम बात यह है कि इससे 2008 के हमारे हैकिंग की ज़रूरत नहीं रह जाती. वेब ऑथरिंग की पूरी प्रोसेस को ज़्यादा समझदार, रखरखाव करने लायक, और ज़्यादा बेहतर बनाना, मेरी किताब में हमेशा एक अच्छी चीज़ होती है.

ज़्यादा रिसॉर्स