If you like this article I suggest you check out my other ones at my blog . Hi, it's me, , one of the maintainers of , a fast embeddable template engine. In this tutorial I will show to create an isomorphic (browser/node) JavaScript template engine. @shadowtime2000 Eta The Design The initial design of the template engine will be pretty simple. It will simply interpolate values from a object. It will use to interpolate values. data {{valueName}} Simple Rendering First, lets create a simple rendering function which takes the template and the data and it will render the value. render = { template.replace( , (match) => { data[match.split( ).filter( )[ ]] }) } var ( ) => template, data return /{{(.*?)}}/g return /{{|}}/ Boolean 0 Basically, all that does is search for anything that is surrounded by the brackets, and it replaces it with the name inside . You can write your templates like this and it will take it from the data object. data Hi, my name is {{name}} ! render( , { : }); "Hi, my name is {{name}}!" name "shadowtime2000" But there is a problem, you can't have spaces in the interpolations. render( , { : }) "Hi, my name is {{ name }}!" name "shadowtime2000" /* Hi, my name is undefined! */ This requires you to have spaces inside the data object, which isn't that clean. We can make it allow spaces by trimming leading and ending whitespace of the data name before interpolating. render = { template.replace( , (match) => { data[match.split( ).filter( )[ ].trim()] }) } var ( ) => template, data return /{{(.*?)}}/g return /{{|}}/ Boolean 0 This is pretty good, but for larger templates it wouldn't be that fast because it has to kind of parse it every time. That is why many template engines support compilation, where the template is compiled into a faster JS function which can take the data and interpolate it. Let's add compilation to our template engine, but before we do, we need to add a special parsing function. Parsing Since parsing can be a little boring, let's just reuse some code from another JS template engine. I would have used the Eta parsing engine, but that has been extremely optimized and can be pretty confusing to people. So, lets use another popular JS template engine parsing code, . Do remember to attribute them for the parsing engine. mde/ejs parse = { result = .exec(template); arr = []; firstPos; (result) { firstPos = result.index; (firstPos !== ) { arr.push(template.substring( , firstPos)); template = template.slice(firstPos); } arr.push(result[ ]); template = template.slice(result[ ].length); result = .exec(template); } (template) arr.push(template); arr; } var ( ) => template let /{{(.*?)}}/g const let while if 0 0 0 0 /{{(.*?)}}/g if return What this basically does is loop over executing the regex pattern on the template and adding the stuff to a data structure. Here is what that data structure would look like: [ , , ] "Hi my name is " "{{ name }}" "!" Now that we have parsing done, lets move on to compilation. Compilation Let's take a quick overview of what compilation would output. Imagine you enter this template: Hi my name is {{ name }} ! It will give you this function: { +data.name+ ; } ( ) function data return "Hi my name is " "!" Let's first create a function to parse and then create a string that can be used. We first have to parse the template. compileToString = { ast = template; } const ( ) => template const We also have to create a string which will be used as the function. compileToString = { ast = template; fnStr = ; } const ( ) => template const let `""` The reason we are using quotation marks at start is because when it is compiling the templates and such, they will all begin with a . Now we have to iterate over the AST. + compileToString = { ast = template; fnStr = ; ast.map( { (t.startsWith( ) && t.endsWith( )) { fnStr += ; } { fnStr += ; } }); } const ( ) => template const let `""` => t // checking to see if it is an interpolation if "{{" "}}" // append it to fnStr `+data. ` ${t.split( ).filter( )[ ].trim()} /{{|}}/ Boolean 0 else // append the string to the fnStr `+" "` ${t} The final part of this function is to return the function string. compileToString = { ast = template; fnStr = ; ast.map( { (t.startsWith( ) && t.endsWith( )) { fnStr += ; } { fnStr += ; } }); fnStr; } const ( ) => template const let `""` => t // checking to see if it is an interpolation if "{{" "}}" // append it to fnStr `+data. ` ${t.split( ).filter( )[ ].trim()} /{{|}}/ Boolean 0 else // append the string to the fnStr `+" "` ${t} return So if it takes this template: Hi my name is {{ name }} ! It will return this: + +data.name+ "" "Hello my name is " "!" Now this is done, creating a compile function is relatively simple. compile = { ( , + compileToString(template)) } const ( ) => template return new Function "data" "return " Now we have completed compilation for our template engine. Wrapping Up In this tutorial I showed how to: Implement a simple rendering function Understand a parsing engine adapted from EJS Iterate over the AST to create fast compiled template functions