Load/Serve a Simple HTML File in Node.js

We have built a simple Node.js HTTP web server in our previous tutorial. But that was just for plain texts. If you have to include some HTML tags along with the text, it will not render as you wish it.

For example, if the res.end('Hello, World\n') statement from our previous code is changed to

					
					  res.end('<h1>Hello, World!</h1> \n');	
					
				

the HTML tags will not be parsed and it will render as follows:

Fixing this requires just a small change by setting the Content-Type of setHeader() to text/html.

					
					const http = require('http');
					const hostname = '127.0.0.1';
					const port = 3000;
					const server = http.createServer((req, res) => {
					  res.statusCode = 200;
					  res.setHeader('Content-Type', 'text/html');
					  res.end('<h1>Hello, World!</h1> \n');
					});
					server.listen(port, hostname, () => {
					  console.log(`Server running at http://${hostname}:${port}/`);
					});
					
				

That was some simple text enclosed between an <h1> tag. But what if we have to serve an entire proper HTML 5 file? This is what we will be learning in this tutorial post.

Since we will be running our project locally, we set the hostname variable to 127.0.0.1. The port variable is set to 3000, so when the server is up, it will listen on port 3000. The fs module allows you to read a file and serve it over HTTP (or HTTPS). The http module's createServer() method returns an instance of the HTTP web server object. It also takes two arguments: an options object, followed by a requestListener function (the callback function here) which is called everytime the request event is triggered.

Serving an HTML File

We will load the below index.html file, located in the same root directory as server.js.

					
						<!DOCTYPE html>
						<html>
						<head>
							<title>Node.js</title>
						</head>
						<body>
							<h1>Hello, Node.js</h1>
						</body>
						</html>
					
				

We use the fs.stat() method to first check the existence of the file. Earlier, the fs.exists() method could as well have been used, but it is already deprecated.

The content type of the header is set to text/html inside the setHeader() method belonging to the res object of the callback function. The fs.createReadStream() function opens up a readable stream. If a file path is passed to it, it starts streaming. The pipe() method helps pipe out a readable stream from source to destination.

					
						const http = require('http');
						const fs = require('fs');
						const hostname = '127.0.0.1';
						const port = 3000;
						const server = http.createServer((req, res) => {
						  if(req.url === '/') {
						  	const htmlFile = 'index.html';
						  	fs.stat(`./${htmlFile}`, (err, stats) => {
						  		if(stats) {
						  			res.statusCode = 200;
						  			res.setHeader('Content-Type', 'text/html');
								  	fs.createReadStream(htmlFile).pipe(res);
						  		}
						  	});
						  }
						});
						server.listen(port, hostname, () => {
						  console.log(`Server running at http://${hostname}:${port}/`);
						});
					
				

Now if you type

					
						http://localhost:3000
					
				

on the browser's address bar, it will render as follows:

Now we will do a little alteration to load this index.html file on accessing it via the path /index.html. This is being done considering the impending need to load other files as well, such as about.html, services.html, privacy.html, etc., when accessed via their respective paths /about.html, /services.html, /privacy.html, etc.

					
						const http = require('http');
						const fs = require('fs');
						const hostname = '127.0.0.1';
						const port = 3000;
						const server = http.createServer((req, res) => {
						  if(req.url === '/index.html') {
						  	const htmlFile = req.url.slice(1);
						  	fs.stat(`./${htmlFile}`, (err, stats) => {
						  		if(stats) {
						  			res.statusCode = 200;
						  			res.setHeader('Content-Type', 'text/html');
								  	fs.createReadStream(htmlFile).pipe(res);
						  		}
						  	});
						  }
						});
						server.listen(port, hostname, () => {
						  console.log(`Server running at http://${hostname}:${port}/`);
						});
					
				

So now, if you type

					
						http://localhost:3000/index.html
					
				

on the browser's address bar, accessing the page /index.html will also render as follows:

Now coming to the need to load other pages like about.html, services.html, privacy.html, etc., proceeding the above way, we may have to write as many if conditions (as such below) as the number of pages.

					
					if(req.url === '/index.html')
					
				

Which means, for 100 pages, you may have to write 100 if conditions. This actually is cumbersome. We can avoid this need for multiple if checks using the endsWith() method to check for .html files as shown below. It will now load any existing HTML file in your project on accessing it by its name and extension.

					
					const http = require('http');
					const fs = require('fs');
					const hostname = '127.0.0.1';
					const port = 3000;
					const server = http.createServer((req, res) => {
					  if(req.url.endsWith('.html')) {
					    const htmlFile = req.url.slice(1);
					    fs.stat(`./${htmlFile}`, (err, stats) => {
					      res.statusCode = 200;
					      res.setHeader('Content-Type', 'text/html');
					      if(stats) {
					        fs.createReadStream(htmlFile).pipe(res);
					      } else {
					      	res.statusCode = 404;
					        res.end('Sorry, page not found');
					      }
					    });
					  }
					});
					server.listen(port, hostname, () => {
					  console.log(`Server running at http://${hostname}:${port}/`);
					});