Updated:

✒ Reference: Node.js tutorial from W3 schools, Beginner’s Guide by Fireship

What is Node.js?

“An asynchronous event-driven JavaScript runtime”

  • asynchronous: Node pushes intensive operations off to a separate thread so only very fast, non-blocking operations happen on the main thread. (non-blocking) This makes Node.js suitable for things that require high-throughput. (real time apps, web servers, etc.)
  • event-driven: You listen to events by registering a callback function, which is only called when the event is triggered.

Node.js is an open source server environment that runs on various platforms, and uses JavaScript on the server. Node.js runs single-threaded, non-blocking, asynchronous programming, which is memory efficient.

What can Node.js do?

  • Generate dynamic page content
  • Create, open, write, delete, and close files on the server
  • Collect form data
  • Add, delete, and modify data in your DB

What is a Node.js file?

Node.js files have extension “.js”, and contain tasks that will be executed on certain events. A typical event would be someone trying to access a port on the server.

How do you use Node.js?

  1. Download Node.js from the official website: https://nodejs.org
  2. Create a Node.js file
  3. Initiate the file in the command line interface of your computer:
    • Navigate to the folder where you saved the Node.js file
    • Initiate the file: i.e. node myfile.js
  4. Now the computer works as a server. If anyone tries to access your computer on the specific port, they get to see your page.

Packages

A package in Node.js contains all the files you need for a module. You can download and use thousands of free packages from https://www.npmjs.com. NPM is a package manager for Node.js packages.

Downloading a package

To download a package, you can use the command line interface: npm install upper-case will download a package called “upper-case”.

NPM creates a folder named “node_modules”, and places all packages that are installed within the folder.

Using a package

Once the package is installed, it is ready to use. Below is a Node.js file that will contert the output into upper-case letters.

// Include the "upper-case" package:
import { upperCase } from 'upper-case';
import { createServer } from 'http';

// demo_uppercase.js
createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/html'});
  res.write(upperCase("hello world!"));
  res.end();
}).listen(8080);

Modules

Modules are equivalent to JavaScript libraries: they are sets of functions you want to include in your application. Node.js has a set of built-in modules you can use without installation. (See the list of Built-in Modules here)

Creating your own module

The properties and methods saved in the function below are now available outside the module file. It can be saved as myfirstmodule.js.

export function myDateTime () {
  return Date();
}

Using the module in any Node.js file:

import { createServer } from 'http';
import { myDateTime } from './myfirstmodule.js';

http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/html'});
  res.write("The date and time are currently: " + dt.myDateTime());
  res.end();
}).listen(8080);

The ES Module

For versions 13.2 and higher, Node.js has stable support of the ECMAScript modules (ES modules in short) which include statements such as import and export.

You can either:

  • Set the module’s file extension as .mjs or
  • Add package.json in the nearest parent folder and include { "type" : "module" }
// inside package.json:
{
  "type" : "module",
  // ...
}

The default format of modules in Node.js is the CommonJS. By modifying the "type" field as "module" in package.json, you are explicitly enabling the ES modules to execute all .js files in the same directory as ECMAScript modules.

The HTTP module

The HTTP module can create an HTTP server that listens to server ports and gives a response back to the client.

A function passed into the http.createServer method will be executed when someone tries to access the computer on the port specified via .listen().

// Include the HTTP module
import { createServer } from 'http';

createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/html'});
  res.write('Hello World!'); 
  res.end(); 
}).listen(8080); 
  • .createServer(function (req, res) => {...}).listen(8080)
    • Create a server object, and listen on port 8080
    • req argument: The requset from the client as an object
    • res argument: The response to the server as an object

  • .writeHead(200, {'Content-Type': 'text/html'})
    • If the response from the HTTP server is displayed as HTML, an HTTP header with the correct content type should be included.
    • First argument: Status code (200: all is ok)
    • Second argument: An object containing the response headers

  • .write('Hello World!') Write a response to the client
  • .end() End the response

Reading the query string

The req argument passed into the .createServer() method represents the request from the client as an object (http.IncomingMessage object). This object has a property called “url” which holds the part of the url that comes after the domain name.

// Read the url of req:
import { createServer } from 'http';

createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/html'});
  res.write(req.url);
  res.end();
}).listen(8080);

After saving the code above and initiating the file, the address http://localhost:8080/summer will provide the result /summer.

The URL module: splitting a web address

The URL module splits up a web address into readable parts; .parse() method of the URL module takse a URL string, parses it, and returns a URL object.

var url = parse(urlString, [parseQueryString], [slashesDenoteHost])
  • urlString: The URL string to parse
  • [parseQueryString]: A boolean value, default false
    • if true, the query property will always be set to an object returned by the querystring module’s parse() method. ({'query':'string'})
    • if false, the query property of the returned value will be an unparsed, undecoded string. (query=string)
  • [slashesDenoteHost]: A boolean value, default false
    • if true, the first token after the literal string // and preceding the next / will be interpreted as the host.
    • i.e. given //foo/bar, the result would be {host: 'foo', pathname: '/bar'} rather than {pathname: '//foo/bar'}.
// Split the query string into readable parts:
import { createServer } from 'http';
import { parse } from 'url';

createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/html'});
  var q = parse(req.url, true).query;
  var txt = q.year + " " + q.month;
  res.end(txt);
}).listen(8080);

After saving the code above and initiating the file, the address http://localhost:8080/?year=2017&month=July will provide the result 2017 July.

The File System module: Node.js as a File Server

The File System module allows you to work with the file system on your computer. Common use for the module:

  • Read files
  • Create files
  • Update files
  • Delete files
  • Rename files

Read files

The readFile() method of the File System module reads the HTML file and returns the content.

// An HTML file in the same folder as Node.js:
<html>
  <body>
    <h1>My Header</h1>
    <p>My paragraph.</p>
  </body>
</html>

// A Node.js file that reads the HTML file and return the content:
import { createServer } from 'http';
import { readFile } from 'fs';

createServer(function (req, res) {
  readFile('demofile1.html', function(err, data) {
    res.writeHead(200, {'Content-Type': 'text/html'});
    res.write(data);
    return res.end();
  });
}).listen(8080);

After saving the code above and initiating the file, you will see the file rendered at http://localhost:8080.

Create & Update Files

The File System module has methods for creating and updating new files:

  • appendFile() appends specified content to a file.
    If the file does not exist, the file is created.

    import { appendFile } from 'fs';
    
    appendFile('mynewfile1.txt', 'Hello content!', function (err) {
        if (err) throw err;
        console.log('Saved!');
    });
    
  • open() takes a “flag” as the second argument. If the flag is “w” for “writing”, the specified file is open for writing.
    If the file does not exist, an empty file is created.

    import { open } from 'fs';
    
    open('mynewfile2.txt', 'w', function (err, file) {
      if (err) throw err;
      console.log('Saved!');
    });
    
  • writeFile() replaces the specified file and content if it exists.
    If the file does not exist, a new file containing the specified content is created.

    import { writeFile } from 'fs';
    
    writeFile('mynewfile3.txt', 'Replaced content!', function (err) {
      if (err) throw err;
      console.log('Saved!');
    });
    

Delete Files

.unlink() method deletes the specified file.

import {unlink} from 'fs';

unlink('mynewfile2.txt', function (err) {
  if (err) throw err;
  console.log('File deleted!');
});

Rename Files

.rename() method renames the specified file.

import { rename } from 'fs';

rename('mynewfile1.txt', 'myrenamedfile.txt', function (err) {
  if (err) throw err;
  console.log('File Renamed!');
});

Making Node.js behave as a file server

You can combine the methods above to create a Node.js file that opens the requested file and returns the content to the client. A 404 error is thrown if anything goes wrong.

// summer.html:
<!DOCTYPE html>
<html>
  <body>
    <h1>Summer</h1>
    <p>I love the sun!</p>
  </body>
</html>

// winter.html:
<!DOCTYPE html>
<html>
  <body>
    <h1>Winter</h1>
    <p>I love the snow!</p>
  </body>
</html>

// demo_fileserver.js:
import { parse } from 'url';
import { readFile } from 'fs';
import { createServer } from 'http';

createServer(function (req, res) {
  var q = parse(req.url, true);
  var filename = "." + q.pathname;
  readFile(filename, function (err, data) {
    if (err) {
      res.writeHead(404, {'Content-Type': 'text/html'});
      return res.end("404 Not Found");
    }
    res.writeHead(200, {'Content-Type': 'text/html'});
    res.write(data);
    return res.end();
  });
}).listen(8080);

After saving the code above and initiating the file, the address http://localhost:8080/summer.html will render the file summer.html and the address http://localhost:8080/winter.html will render the file winter.html

The Events module: handling Events

Objects in Node.js can fire events. (i.e. readStream object fires events when opening and closing a file.)

All event properties and methods are an instance of an event emitter object. You need to create an object to access the properties and methods.

import { EventEmitter } from 'events';
var eventEmitter = new EventEmitter();

//Create an event handler:
var myEventHandler = function () {
  console.log('I hear a scream!');
}

//Assign the event handler to an event:
eventEmitter.on('scream', myEventHandler);

//Fire the 'scream' event:
eventEmitter.emit('scream');

The Formidable module: uploading files

The Formidable module allows you to create a web page in Node.js where the user can upload files to your computer.

This module should be downloaded and installed using NPM, by running npm install formidable on command.

  1. Create an upload form
    Create a Node.js file that writes an HTML form, with an upload field.
  2. Parse the uploaded file
    Once the uploaded file reaches the server, the Formidable module allows parsing it.
  3. Save the file
    Once the file is successfully uploaded, it gets placed on a temporary folder on your computer. The path to this directory can be found in the “files” object, passed as the third argument in the .parse() method’s callback function. To move the file, rename it via the .rename() method of the File System module.
// Create a Node.js file that writes an HTML form, with an upload field:
import { createServer } from 'http';
import { IncomingForm } from 'formidable';
import { rename } from 'fs';

createServer(function (req, res) {
  // 2. Parse the file when it is uploaded
  if (req.url == '/fileupload') {
    var form = new IncomingForm();
    form.parse(req, function (err, fields, files) {
      // 3. Save the file
      var oldpath = files.filetoupload.filepath;
      var newpath = 'C:/Users/YourName/' + files.filetoupload.originamFilename;
      rename(oldpath, newpath, function (err) {
        if (err) throw err;
        res.write('File uploaded and moved!');
        res.end();
      });
    });
  } else {
    // 1. Write an HTML form with an upload field.
    res.writeHead(200, {'Content-Type': 'text/html'});
    res.write('<form action="fileupload" method="post" enctype="multipart/form-data">');
    res.write('<input type="file" name="filetoupload"><br>');
    res.write('<input type="submit">');
    res.write('</form>');
    return res.end();
  }
}).listen(8080);

The Nodemailer module: sending emails

The Nodemailer module makes it easy to send emails from your computer server.

This module should be downloaded and installed using NPM, by running npm install nodemailer on command.

Sending an email

Use the username and password from your selected email provider to send an email. A server with the following code is able to send emails!

You can send an email to more than one receiver by adding them to the “to” property of the mailOptions object.

import { createTransport } from 'nodemailer';

var transporter = createTransport({
  service: 'gmail',
  auth: {
    user: 'youremail@gmail.com',
    pass: 'yourpassword'
  }
});

var mailOptions = {
  from: 'youremail@gmail.com',
  // multiple receivers
  to: 'myfriend@yahoo.com, myotherfriend@yahoo.com',
  subject: 'Sending Email using Node.js',
  text: 'That was easy!'
};

transporter.sendMail(mailOptions, function(error, info){
  if (error) {
    console.log(error);
  } else {
    console.log('Email sent: ' + info.response);
  }
});

You can send HTML formatted text in your email, by using the html property instead of the text property:

var mailOptions = {
  from: 'youremail@gmail.com',
  // multiple receivers
  to: 'myfriend@yahoo.com, myotherfriend@yahoo.com',
  subject: 'Sending Email using Node.js',
  html: '<h1>Welcome</h1><p>That was easy!<p>'
};

Leave a comment