By Md. Sabuj Sarker | 7/25/2018 | General |Beginners

Node.js Backend Development - Implementing a Templating System

Node.js Backend Development - Implementing a Templating System

Templates are an inseparable part of almost any web application. We have made our application dynamic in various aspects, but we did not make a dynamic templating system—we were just serving plain old HTML. Again, we do not want to use any third party library or framework for templating. Instead, we want to create our own.

In the previous article, we learned about a few of the global objects that are available in Node.js. The code of all the articles can be found on the Github repository Learn Node.js With Sabuj. Code for each article is separated into branches on the repository. Codes for this current article can be found in the branch named 010_custom_templating_system.

We want to keep our template files inside a directory called templates inside the project root directory. Let's create the directory and create a .gitignore file inside of it so that Git does not discard it when the directory is empty.

Now we need to create a module called templating inside custom_modules. We will export a function called render() from inside of it.

templating.js

exports.render = function(template_name, value_pack, callback){

}

This function will accept three parameters. The first one is the template name, it is literally the file name inside the templates directory. The second parameter named value_pack is a key value pair and the third parameter is a callback function when that will be called when the processing is complete.

Now, we need to decide what our template language will look like. We are not going to develop a full featured template language here. We are going to create a very simple logicless template language. Our templating system will scan for "{{ an_identifier }}" pattern and it will place a value from the value_pack. The identifier must only contain English letters, digits, and underscores. It can start with digits unlike variables, and also unlike variables, it cannot contain the dollar sign.

Before we start coding our simple templating system we need to set up other things. Create a route in our routes like below:

var home = require("./views/home").home;
var form = require("./views/form").form;
var process_form = require("./views/process_form").process_form;
var view_404 = require("./views/view_404").view_404;
var static_files = require("./views/static_files").static_files;
var globalo = require("./views/globalo").globalo;
var templated_view = require("./views/templated_view").templated_view;

var routes = [
   {
       pattern: '',
       handler: home
   },
   {
       pattern: 'form',
       handler: form
   },
   {
       pattern: 'submit-form',
       handler: process_form
   },
   {
       pattern: 'static/',
       handler: static_files 
   },
   {
       pattern: 'globalo',
       handler: globalo
   },
   {
       pattern: 'templated_view',
       handler: templated_view
   }
]

exports.routes = routes;
exports.view_404 = view_404;

Now create the templated view inside the views directory.

templated_view.js

exports.templated_view = function(request, response, url){

}

We also want to create an HTML file inside the templates directory named my_template.html

<!doctype html>
<html>
   <head>
       <title>Learning Node.js with Sabuj</title>
   </head>
   <body>
       <h1> A Header {{ random_no }}</h1>
       <p>Random Timestamp: {{ now }}</p>
   </body>
</html>

So, we want to insert a random number and the current date-time stamp multiplied by another random number inside the template.

The templated view now looks like below:

templated_view.js

var render = require('../custom_modules/templating').render;

exports.templated_view = function(request, response, url){
   render('my_template.html', {
       random_no: Math.random() * 100,
       now: Date.now() * Math.random()
   },
   function(data){
       response.writeHead(200, {
           'Content-Type': 'text/html'
       });
       response.end(data);
   }
   );
}

It imports and calls the render() function by passing the values object with random_no and now keys. It also passes a callback function that will be responsible for writing headers and sending the rendered data.

The template rendering code is as below:

var fs = require('fs');

exports.render = function(template_name, values, callback){
   var str_array = [];
   var last_idx = 0;
   fs.readFile('templates/' + template_name, 'utf8', function(err, data){
       var re = /({{\s*([0-9a-zA-Z_]+)\s*}})/g;
       data.replace(re, function(match, full, identifier, idx) {
           str_array.push(data.slice(last_idx, idx) + values[identifier]);
           last_idx = idx + full.length;
       });

       if (last_idx !== data.length - 1){
           str_array.push(data.slice(last_idx, data.length));
       }

       callback(str_array.join(""));
   });
}

It uses regular expression. First of all, it creates a string array that will contain the chunks of strings after every replacement of the keys with values. A variable called last_idx is keeping the index in the string where the last match of the format "{{ identifier }}" ended. A variable called re is a Regular Expression object that contains the pattern of our logicless template language. We are invoking the replace() function on the string identified by data and then we are properly inserting the values provided by the view as a key-value object where the identifier resembles the key in the object. As a replacement strategy, we did not follow plain string replacement. Instead, we passed the pattern as the first parameter and a replacement function callback as the second parameter. In the replacement function, we passed the match, the first group match, the second group match, and the matching index. We are replacing the values of the template identifier and then pushing them into the temporary array. At the end we are checking if any substring from the original string is left behind; if so, we are pushing that to the array too. Finally, we are joining all the substrings in the array and calling the callback that in turn returns the result to the browser.

Now, fire up the terminal, run the main script, go to the browser and browse: http://localhost:5000/templated_view — you will be greeted with a result something like below:

A Header 41.17405893777466
Random Timestamp: 521860341962.9128

So, we have finally developed our Node.js application that can act as a micro framework for any of our future projects that will make our life much easier. In future articles I will introduce more and more features. After covering core concepts we will go back and integrate the Angular application with the Node.js backend application. Keep practicing Node.js and keep updated with this blog.

 

Previous article: Global Objects

Next article: coming soon!

 

About the Author

My name is Md. Sabuj Sarker. I am a Software Engineer, Trainer and Writer. I have over 10 years of experience in software development, web design and development, training, writing and some other cool stuff including few years of experience in mobile application development. I am also an open source contributor. Visit my github repository with username SabujXi.

By Md. Sabuj Sarker | 7/25/2018 | General

{{CommentsModel.TotalCount}} Comments

Your Comment

{{CommentsModel.Message}}

Recent Stories

Top DiscoverSDK Experts

User photo
3355
Ashton Torrence
Web and Windows developer
GUI | Web and 11 more
View Profile
User photo
3220
Mendy Bennett
Experienced with Ad network & Ad servers.
Mobile | Ad Networks and 1 more
View Profile
User photo
3060
Karen Fitzgerald
7 years in Cross-Platform development.
Mobile | Cross Platform Frameworks
View Profile
Show All
X

Compare Products

Select up to three two products to compare by clicking on the compare icon () of each product.

{{compareToolModel.Error}}

Now comparing:

{{product.ProductName | createSubstring:25}} X
Compare Now