{"id":8093,"date":"2020-04-13T19:29:06","date_gmt":"2020-04-13T19:29:06","guid":{"rendered":"http:\/\/putridparrot.com\/blog\/?p=8093"},"modified":"2020-04-13T19:31:57","modified_gmt":"2020-04-13T19:31:57","slug":"writing-javascript-templates-using-ejs","status":"publish","type":"post","link":"https:\/\/putridparrot.com\/blog\/writing-javascript-templates-using-ejs\/","title":{"rendered":"Writing JavaScript templates using ejs"},"content":{"rendered":"<p>There are quite a few (as you&#8217;d probably expect) templating engines for use with JavaScript, such as <a href=\"https:\/\/mustache.github.io\/\" rel=\"noopener noreferrer\" target=\"_blank\">Mustache<\/a> and <a href=\"https:\/\/handlebarsjs.com\/\" rel=\"noopener noreferrer\" target=\"_blank\">handlebars<\/a> both of which use {{ }} syntax. <\/p>\n<p>The syntax used is really not very important, what matters is the flexibility\/functionality, but for nostalgia&#8217;s sake (as much as anything) this post will instead use <a href=\"https:\/\/ejs.co\/\" rel=\"noopener noreferrer\" target=\"_blank\">ejs<\/a> which uses syntax such as &lt;%= %&gt; which is very much like old ASP from my recollections (hence the nostalgia).<\/p>\n<p><em>Note: I&#8217;m not endorsing ejs over any other engine, I just picked this to begin with, if\/when I get time I will probably create posts covering using some other templating engines also.<\/em><\/p>\n<p><strong>Getting Started<\/strong><\/p>\n<p>We need to start by installing ejs, so run the following<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nyarn add ejs\r\n<\/pre>\n<p>We&#8217;re going to create a folder named <em>templates<\/em> (this is not a requirement of ejs) to store our .ejs files. So the template files will be saved with the .ejs extension.<\/p>\n<p>Let&#8217;s just create a very standard Hello World app. so in the file <em>templates\/sample.ejs<\/em> write the following<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\n&lt;%= message %&gt;\r\n<\/pre>\n<p>Now let&#8217;s write the code to use ejs generate some output from our template and supply our  data to the generator.<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\nconst ejs = require(&quot;ejs&quot;);\r\n\r\nejs.renderFile(&quot;.\/templates\/sample.ejs&quot;, {\r\n    message: &quot;Hello World&quot;,\r\n  },\r\n  {},\r\n  (err: any, result: string) =&gt; {\r\n    if(err != null) {\r\n      console.log(err);\r\n    }\r\n    \/\/ use the results of the template combined\r\n    \/\/ with the supplied model\r\n    console.log(result);\r\n});\r\n<\/pre>\n<p>Here we show the basic usage pattern, which uses the asynchronous renderFile function. This takes the template file (we can ofcourse also supply the template as a string using the render function). The second argument is a &#8220;model&#8221; of the data being passed into the template engine and ofcourse the key&#8217;s related to the variable names used within the template file. The third argument supplies any options to the template engine, in this example I&#8217;m not applying any options. Finally, as this function is asynchronous, we will get an error or result or the processing of the template.<\/p>\n<p><strong>More&#8230;<\/strong><\/p>\n<p>That was simple enough but we&#8217;re not going to want to just output simple values like this, so let&#8217;s take a look at some more capabilities.<\/p>\n<p>If we take a look at the Docs (https:\/\/ejs.co\/#docs), Tags section we can see the tags for embedding our model data, let&#8217;s take a look at some of these in usage.<\/p>\n<p><strong><em>&lt;%<\/em><\/strong><\/p>\n<p>The scriptlet tag is used for flow control and does not embed output into the template itself (as such). Instead it allow us to use conditionals such as if or loops such as for loops on our data model items.<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\ntype Names = &lt;% for(let i = 0; i &lt; names.length; i++) { %&gt;\r\n    | '&lt;%= name&#x5B;i].header %&gt;'&lt;% } %&gt;;\r\n<\/pre>\n<p>In this example we&#8217;re code generating some types by taking an array of <em>names<\/em> from the model and creating a union of those <em>header<\/em> names.<\/p>\n<p>Like-wise we might also use this tag for if statements within the &lt;% %gt; <\/p>\n<p><strong>&lt;%_<\/strong><\/p>\n<p>This will strip whitespace from before the tag. One of the problems we often find with templated code generation is how to control whitespace before and after the generated code. Hence this will remove the preceding whitespace.<\/p>\n<p><strong>&lt;%=<\/strong><\/p>\n<p>This simply embeds an HTML escaped value into our template, in other words it simply replaces the tag with the value from <em>message<\/em> in this example below. Ofcourse <em>message<\/em> is a value stored in our data model.<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\n&lt;%= message %&gt;\r\n<\/pre>\n<p><strong>&lt;%-<\/strong><\/p>\n<p>As per &lt;%= but no escaping of values takes place. <\/p>\n<p><strong>&lt;%#<\/strong><\/p>\n<p>Comment tags, just in case you wanted to add some comments\/documentation to your template, this does not get output as part of the generated data.<\/p>\n<p><strong>&lt;%%<\/strong><\/p>\n<p>Escapes the tag, i.e. outputs &lt;%<\/p>\n<p><strong>%&gt;<\/strong><\/p>\n<p>Standard end tag for use with the other start tags.<\/p>\n<p><strong>-%&gt;<\/strong><\/p>\n<p>Trims the following newline.<\/p>\n<p><strong>_%&gt;<\/strong><\/p>\n<p>Removes whitespace after the tag, again allows us to have some control of the whitespace following our generated output.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>There are quite a few (as you&#8217;d probably expect) templating engines for use with JavaScript, such as Mustache and handlebars both of which use {{ }} syntax. The syntax used is really not very important, what matters is the flexibility\/functionality, but for nostalgia&#8217;s sake (as much as anything) this post will instead use ejs which [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[71,294,45],"tags":[],"class_list":["post-8093","post","type-post","status-publish","format-standard","hentry","category-code-generation","category-ejs","category-javascript"],"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/8093","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/comments?post=8093"}],"version-history":[{"count":5,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/8093\/revisions"}],"predecessor-version":[{"id":8105,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/8093\/revisions\/8105"}],"wp:attachment":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/media?parent=8093"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/categories?post=8093"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/tags?post=8093"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}