- Create simple web site with Node.js

Using Node.js URL Module

An important part of a web page is the URL address. The URL module splits up a web address into readable parts.
This module can be used to create a Node.js script that displays html content according to URL address.
To include the URL module, use the require() method:
const url = require('url');
Now, lets parse an URL address, using the url.parse() method. It will return a URL object with each part of the address as properties:
var url = require('url');
var adr = 'http://localhost:8080/index?id=890&ctg=nodejs';
var p = url.parse(adr, true);

console.log(p.host); //returns localhost:8080
console.log(p.pathname); //returns /index
console.log(p.search); //returns ?id=890&ctg=nodejs

var q = p.query; //contains an object: {id:890, ctg:'nodejs'}
console.log(q.id); //returns 890

Split URL.search string

You can use the query property of the url.parse() method to split the search query string into readable parts. So, to can display different content according to data from URL query.
Example, split the query string into readable parts, and display the resulted object into a JSON string in page.
//include http and url modules
const http = require('http');
const url = require('url');

//create the server
const server = http.createServer((req, res)=> {
  res.writeHead(200, {'Content-Type':'text/html; charset=utf-8'}); //adds header to display html content with utf-8

  //parse the url, get object with {name:value} from url query
  var sq = url.parse(req.url, true).query;
  var src_data ='<h4>'+JSON.stringify(sq)+'</h4>';
  src_data +='id = '+sq.id+'<br>nm = '+sq.nm;

  res.write(src_data, 'utf-8');
  res.end();
});

server.listen(8080, ()=> {
  console.log('Server running at //localhost:8080/');
});
Save the code above in a file called "demo_url_query.js" and initiate the file with node in the command line interface.
Access in your browser the address: //localhost:8080/?id=1&nm=admin
Will produce this result:

{"id":"1","nm":"admin"}

id = 1
nm = admin

Create simple web site

Now we know how to parse the URL address, and to make Node.js behave as a server. In the previous tutorials we have learned how to use the "fs" module to read a file content.
Let us combine what we have learned to create a simple Node js website with categories and pages that serve the page requested by the client.

• For this project you can create the files with the code presented in this page, or ..:
- Click this link to download the whole script: Get Node.js Simple WebSite.

• To see a Demo, click: Demo Node.js Simple WebSite.

1. Create the html template file

First, create a folder called "site1", in the same directory as your node.js.
In the "site1/" folder create a file called "tpl_index.htm" with a template html document, and a responsive design; which we'll use to serve the html page content.
- Here is the code for "tpl_index.htm" file:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>{${title}}</title>
<meta name="description" content="{${description}}"/>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style>
body, html {
position:relative;
background:#f2f3fe;
margin:0;
padding:0;
text-align:center;
font-size:1em;
font-family:"Calibri",sans-serif;
}
header {
background:#fafaff;
border:1px solid #888;
}
h1 {
margin:1px auto 8px auto;
}

#menu_top{
position:relative;
margin:3px auto;
padding:0;
font-size:16px;
font-weight:700;
}
#menu_top a{
margin:1px 2px;
background-color:#8f9fde;
padding:1px 4px;
text-decoration:none;
color:#fff;
box-shadow:.15em .13em .25em #6789da inset;
-webkit-box-shadow:.15em .13em .25em #6789da inset;
border-radius:.5em;
background-image:-ms-linear-gradient(top, #0818be, #b0c0fb);
background-image:-moz-linear-gradient(top, #0818be, #b0c0fb 95%);
background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0, #0818be), color-stop(0.9, #b0c0fb));
background-image:-o-linear-gradient(top, #0818be, #b0c0fb);
background:linear-gradient(top, #0818be, #b0c0fb);
}
#menu_top a:hover{
background:#fbfb01;
text-decoration:underline;
color:#0408fe;
box-shadow:.15em .13em .25em #a0a0da;
-webkit-box-shadow:.15em .13em .25em #a0a0da;
}

/* Side Menu */
#menu_side {
position:absolute;
top:100px;
left:1px;
width:200px;
padding:2px 1px 8px 0;
text-align:center;
}
#menu_side h4 {
margin:-.7em .8em .1em .7em;
background-color:#eaebfe;
padding:1px;
box-shadow:.15em .13em .25em #6789da inset;
border-radius:.5em;
background:linear-gradient(top, #dddefe, #eeeffe);
text-align:center;
}
#menu_side ul {
position:relative;
margin:0;
padding:0;
background:#f9f9eb;
border-radius:.6em;
list-style-type:none;
font-size:17px;
text-align:left;
}
#menu_side a {
display:block;
padding:2px 0 1px 4px;
color:#0000c0;
}
#menu_side > ul > li:hover, #menu_side > ul > li a:hover {
background:#3434fe;
color:#ffffff;
text-decoration:none;
}

#content {
background:#fefefe;
position:relative;
margin:25px 2px 5px 215px;
}

/* mobile dev. */
@media screen and (max-width: 650px){
@keyframes slide_top {
0% { margin-top:100px; }
100% { margin-top:0; }
}
header {
margin:1px 1px 3px 28px;
}
#menu_top {
font-size:14px;
line-height:150%;
margin:0 25px 1px 23px;
}
#menu_top a {
margin:2px 1px 2px 2px;
padding:0 2px;
font-weight:700;
}
#menu_top a:hover {
background:yellow;
color:#0408fe;
}

/* Side Menu */
#menu_side {
left:0;
top:35px;
background:#bedacf;
padding:3px;
border-radius:5px;
z-index:8888;
width:auto;
}
#menu_side h4  {
background-color:transparent;
box-shadow:none;
background:none;
font-size:18px;
line-height:85%;
width:20px;
margin:0;
padding:0;
}
#menu_side ul {
 background:none;
 display:none;
}
#menu_side ul li {
 margin:2px auto;
 background:#e0e0fb;
 padding-left:1px;
}
#menu_side:hover h4 { display:none;}
#menu_side:hover ul {
display:block;
animation-name: slide_top;
animation-duration: 1s;
animation-timing-function: ease-in-out;
animation-delay: 0s;
animation-fill-mode: forwards;
}

#content {
margin:15px 1px 3px 28px;
}
}
</style>
</head>
<body>
<header>
<h1>{${title}}</h1>
<nav id="menu_top">{${menu_header}}</nav>
</header>
<section id="content">{${content}}</section>
<nav id="menu_side">
<h4>M E N U</h4>
{${menu_side}}
</nav>
</body>
</html>

2. The folder for files with pages content

In "site1/" directory create another folder called "content". In this folder we'll store ".htm" files with the content for each page of the site.
Also, in the "content/" folder we create a ".json" file, called "pages.json" that contains a JSON object with data for categories and their pages.
The first category "/" is for index /home page and other pages in this category.
- Here is the code for "pages.json" file, with 3 main categories and 5 pages:
{
 "/":{
  "title":"Title home page",
  "description":"Description home page",
  "link_txt":"Home",
  "pages":{
   "contact":{
    "title":"Contact page",
    "description":"Description for contact page",
    "link_txt":"Contact"
   }
  }
 },
 "ctg-1":{
  "title":"Title category one",
  "description":"Description category one",
  "link_txt":"Ctg-One",
  "pages":{
   "page-1":{
    "title":"Title page one",
    "description":"Description page one",
    "link_txt":"Page One"
   },
   "page-2":{
    "title":"Title page two",
    "description":"Description page two",
    "link_txt":"Page Two"
   }
  }
 },
 "ctg-2":{
  "title":"Title category two",
  "description":"Description category two",
  "link_txt":"Ctg-Two",
  "pages":{
   "pg-one":{
    "title":"Title page one in category 2",
    "description":"Description page one in category 2",
    "link_txt":"Page 1"
   },
   "pg-two":{
    "title":"Title page two in category 2",
    "description":"Description page two in category 2",
    "link_txt":"Page 2"
   }
  }
 }
}
- This object contains the Title, Description, and text for link ('link_txt') for each category and pages. These data will be added in template when a page is accessed in browser.
The main content for each page will be stored in separate files (in "content/" folder), having the same name as the name added in "pages.json", and ".htm" extension.
- For example: for 'index' page we create a file called "index.htm" with the html content we want to display in page-body. For the page-body content of the "ctg-1" category we create a file named "ctg-1.htm". And so on for the body content of each category and page, like in this image:
content dir of simple website with Node.js

3. The JS script for page content

Now, we create a module called "setpage.js" in the "site1/" folder, with a JavaScript class that will get and set all the html content for the requested page; with data added in the "content/" folder.
This module will be included with require() in the main.js file.
- Here is the code for "setpage.js" file:
//set the page content according to data from url
class setpage {
  //set propertie
  constructor(){
    this.pages ={} //for categories and pages data stored in pages.json
    this.tpl ='' //store string with html template from tpl_index.htm
    //values for template
    this.tpl_val ={
      title:'',
      description:'',
      menu_header:'',
      menu_side:'',
      content:''
    }
    this.ctg ='/'; //current category
    this.pg =''; //current page
    this.err =[]; //store errors

    //gets pages data from pages.json
    fs.readFile(path.resolve(__dirname, 'content/pages.json'), 'utf8', (err, data)=>{
      if(err) this.err.push(err);
      else {
        this.pages = JSON.parse(data);
        if(this.pages) this.menuHeader(this.pages);
      }
    });

    //gets template from tpl_index.htm
    fs.readFile(path.resolve(__dirname, 'tpl_index.htm'), 'utf8', (err, data)=>{
      if(err) this.err.push(err);
      else this.tpl = data;
    });
  }

  //set $menu_header with links for categories; Receives $ctgs = object with all categories
  menuHeader(ctgs){
    for(var prop in ctgs){
      var href = (prop =='/') ?'' :prop+'/';
      this.tpl_val.menu_header +='<a href="/'+href+'" title="'+ctgs[prop].title+'">'+ctgs[prop].link_txt+'</a>';
    }
  }

  //set $menu_side with links of pages in current category - $pgs
  menuSide(pgs){
    var menu_side ='';
    for(var prop in pgs){
      var href = (this.ctg =='/') ?prop :this.ctg+'/'+prop;
      menu_side +='<li><a href="/'+href+'.htm" title="'+pgs[prop].title+'">'+pgs[prop].link_txt+'</a></li>';
    }
    if(menu_side !='') this.tpl_val.menu_side ='<ul>'+menu_side+'</ul>';
  }

  //sets $pg $ctg with data from url; receives the request
  setPgCtg(req){
    var cp = url.parse(req.url, false, true).pathname.split('/'); //[categories, page]
    this.pg = cp.pop().replace('.htm', '');
    this.ctg = cp.join('');
    if(this.ctg =='') this.ctg ='/';
  }

  //adds page data (title, description, content) in $tpl_val
  pageData(){
    //set name for file content
    if(this.pg !='') var file =this.pg; //page in category
    else if(this.ctg !='/' && this.pg =='') var file = this.ctg; //category
    else var file ='index';

    // sets title and description
    if(this.pages[this.ctg]){
      if(this.pg ==''){ //category
        this.tpl_val.title = this.pages[this.ctg].title;
        this.tpl_val.description = this.pages[this.ctg].description;
      }
      else if(this.pages[this.ctg].pages[this.pg]){ //page
        this.tpl_val.title = this.pages[this.ctg].pages[this.pg].title;
        this.tpl_val.description = this.pages[this.ctg].pages[this.pg].description;
      }
    }

    this.tpl_val.content = fs.readFileSync(path.resolve(__dirname, 'content/'+file+'.htm'), 'utf8');
  }

  //call methods that sets data for current category and template; receives client request from server
  set page(req){
    this.setPgCtg(req);
    if(this.pages[this.ctg] && this.pages[this.ctg].pages) this.menuSide(this.pages[this.ctg].pages);
    this.pageData();
  }

  //return html page document
  get page(){
    //adds errors before content
    if(this.err.length >0) this.tpl_val.content ='<div id="err">'+this.err.join('<br>')+'</div>'+this.tpl_val.content;

    //parse $tpl_val to add data in $tpl; a={${str}}, b=str
    var tpl_val = this.tpl_val;
    var re = this.tpl.replace(/\{\$\{([^\}]+)\}\}/ig, function(a,b){ return tpl_val[b] ? tpl_val[b] :a; });
    return re;
  }
}

//assign object of setpage class to module.exports
module.exports = new setpage();

4. The main.js file for Node.js server

Then, we create a "main.js" file in the "site1/" folder; this will be the Node.js server:
//include needed modules
const http = require('http');
global.fs = require('fs');
global.path = require('path');
global.url = require('url');
const setpage = require('./setpage');

//create the server
const server = http.createServer((req, res)=>{
  res.writeHead(200, {'Content-Type':'text/html; charset=utf-8'}); //adds header to display html content with utf-8

  //call method that sets page data for current request
  setpage.page = req;

  //get and write html page content
  var page = setpage.page;
  res.write(page, 'utf-8');
  res.end();
});

server.listen(8080, ()=> {
  console.log('Server running at //localhost:8080/');
});
- Once all the files are created in the "site1/" directory, run the "site1/main.js" file in command line interface to start the Node.js server:
node site1/main.js
Acces the website in your browser: http://localhost:8080/

• For Demo, click: Demo Node.js Simple WebSite.

• To download all the files of this project, click: Get Node.js Simple WebSite.

Daily Test with Code Example

HTML
CSS
JavaScript
PHP-MySQL
Which tag defines the clickable areas inside the image map?
<map> <img> <area>
<img src="image.jpg" usemap="#map1">
<map name="map1">
  <area shape="rect" coords="9, 120, 56, 149" href="#">
  <area shape="rect" coords="100, 200, 156, 249" href="#">
</map>
Which CSS property defines what is done if the content in a box is too big for its defined space?
display overflow position
#id {
  overflow: auto;
}
Click on the event which is triggered when the mouse is positioned over an object.
onclick onmouseover onmouseout
document.getElementById("id").onmouseover = function(){
  document.write("Have Good Life");
}
Indicate the PHP variable that contains data added in URL address after the "?" character.
$_SESSION $_GET $_POST
if(isset($_GET["id"])) {
  echo $_GET["id"];
}
Create simple web site

Last accessed pages

  1. jQuery parent, children and nth-child() (9501)
  2. Drag Racer V3 (14798)
  3. Master Of The Secret Sea (377)
  4. Volume and Surface Area Calculator for 3D objects (6309)
  5. PHP MySQL - using MySQLi (7674)

Popular pages this month

  1. Qwop (7149)
  2. Drag Racer V3 (4903)
  3. Bubbles3 (1994)
  4. List with All the Games (1669)
  5. Butterfly Kyodai (1590)