An Introduction to

Node.JS

By Kostas Minaidis | Social Hackers Academy

Table of Contents

  • What is Node.JS?
  • Installing Node.JS
  • Hello World App
  • Node REPL
  • Executing JS Files
  • Node Modules
  • Hello World Server App
  • Creating a basic Web Server
  • Opening our App to the World
  • Deploying (Heroku)

What is Node.JS?

A Runtime Environment to run JavaScript outside the Browser. Think: Server-side JavaScript interpreter.

It uses Chrome's V8 JavaScript engine to compile JS commands into executable code.

It is a free and open source software created in 2009 by Ryan Dahl.

Details

  • It's cross-platform and is mainly used to build backend services (APIs, servers, etc.) and Command line tools.
  • Uses the same JavaScript language that the browser uses, but has access to different context and APIs:
    • Browser: document, location, window, accelerometer, geolocation, etc. (Browser APIs)
    • Node: fs (file system), os (operating system), http, etc.
  • Node.js has the largest open source library in the world: The NPM.

Installing Node.JS

1) Go to: https://nodejs.org/en/download/

2) Download the LTS version for your platform and follow the instructions

3) Once installed, open the terminal and check that node has been installed:

$ node --version

You should see something like this:

v14.15.4

What's the difference between
LTS and Current version?

LTS: Stability, rare updates, enterprise-level apps and services, long-term support: 18 months. Better suited for production.

Current/Stable: Front-end tools, local development, regular updates, new features, performance updates, bug fixes, cutting-edge technologies, etc. Support for approximately 8 months.

Bottom line?

Can't / Don't want to install Node.JS?

No problem.
Try out Node.JS in the browser!

Repl.it
RunKit.com

A simple Node.JS app

$ mkdir app
$ cd app
$ touch app.js
console.log('Node!');
$ node app.js

Gotchas

$ code app.js
console.log( window );
$ node app.js
 ReferenceError: window is not defined

We are not running JS in the browser where the window global object is available.

Global Object

Built-in functions such as setTimeout() are available both on Node.JS and the Browser.

On the Browser, these built-in functions are methods of the global window Object, whereas in Node.js they are methods of the global object:

window.setTimeout
global.setTimeout

Node REPL

Read-Eval-Print-Loop

Use the Node REPL to test

Open up your terminal and type

$ node
> 4+6
10

Basic REPL commands

> .exit
> .help
> .break or .clear
> .editor
> .save
> .load
How to clear the console?
> console.clear(); or CTRL+L

Node Modules

Every file in Node is considered a Module.

console.log( module ); 
// NOT a global.module object!
Module {
    ...
    exports: {},
    ...
}

Module global variables available: exports, require, module, __filename, __dirname

Think of each JavaScript file a separate Module with its own private scope and context.

Code

$ touch app.js 
console.log( module ); 
$ node app.js 

*The touch command creates a new file in *nix systems

3 Types of Modules

1) Your own source files

2) Core node modules

3) Installed dependencies in node_modules/ folder

Working with Modules:
Creating a Module

$ touch logger.js
let message = "Module";

function log(){ 
    console.log( message );
}

module.exports = log;

Both log and message are scoped into the module and are not available outside the module (file). We try to export only a minimal amount of variables and keep things private in the Module.

We can also export multiple values:

module.exports.log = log;

Working with Modules:
Loading a Module

app.js:
const logger = require( './logger.js' );
// We must be on the same folder here
console.log( logger );
logger();   // Custom variable name here

We could have used:

require( './folder/logger.js' );

or:

require( '../logger.js' );

BEST PRACTICE: use a const to store require() objects.

Side by Side

logger.js:

module.exports :: Exports -->

let message = "Module";

function log(){ 
    console.log( message );
}

module.exports = log;
app.js:

<-- require() :: Imports

const logger = require("./logger.js");
// We must be on the same folder here
console.log( logger );
logger();

BUILT-IN MODULES

The fs Built-in Module

Synchronous Code

app.js:
const fs = require( 'fs' );
const files = fs.readdirSync( './' );

files will be a String Array

console.log( files );
The fs Built-in Module

Asynchronous Code

app.js:
const fs = require( 'fs' );
const files = fs.readdir( './', ( err,files )=>{

    if ( err ) {
        console.log( err );
    } else {
        console.log( files );
    }

}); 

BEST PRACTICES: Prefer asynchronous methods instead of sync (readdirSync) for non-blocking code.

*Add 2 console.log statements to test asynchronous code

The fs Built-in Module

readFileSync() (Synchronous Code)

app.js:
const fs = require( 'fs' );
let contents = fs.readFileSync( 'app.js' );
console.log( contents );

What do you see in the console?

Let's try again with one small addition...

contents = fs.readFileSync( 'app.js','utf8' );
console.log( contents );

*Add some error handling using try { } catch { }

The fs Built-in Module

readFile() (Asynchronous Code)

app.js:
const fs = require( 'fs' );
fs.readFile( 'app.js', ( err, buffer )=>{
    console.log( buffer.toString() );
});
The fs Built-in Module

writeFile() and writeFileSync

app.js:
const fs = require( 'fs' );

// SYNC:
fs.writeFileSync( 'test.txt', "TEXT DATA" );

// ASYNC:
fs.writeFile( 'test.txt', "TEXT DATA",  ( err )=>{
    if ( err ){
        console.log( err.message );
    }
});

How to append to a file?

fs.appendFile()
fs.appendFileSync()
(*Defaults to UTF8 encoding)

How to delete a file?

fs.unlink()
fs.unlinkSync()
The path Built-in Module
app.js:
const path = require('path'); 
let pathObj = path.parse(__filename);

__filename: The file name of the current module.

{ 
    root: '/',
    dir: '/Users/kostasx/Desktop',
    base: 'app.js',
    ext: '.js',
    name: 'app' 
}
One step further...
app.js:
const path = require('path'); 
let arguments = process.argv;
// process.argv == Array of command line arguments
let pathObj = path.parse( arguments[2] );
console.log( pathObj );

process: global object that provides information about, and control over, the current Node.js process. It is always available to Node.js apps without require();

The os Built-in Module

Information about Operating System
Documentation

app.js:
const os = require('os');

os.totalmem();
os.freemem(); 

console.log( `Total Memory: ${os.totalmem()}` );

Google for: js convert bytes to gb
refactor code to display the total memory in GB

The http(s) Built-in Module

Communication over HTTP(S)
Documentation

app.js:
const https = require('https');
const URL = 'https://api.chucknorris.io/jokes/random';

https.get( URL, (response) => {

    let data = '';

    response.on('data', (chunk) => { data += chunk; });

    response.on('end', () => {
        console.log(JSON.parse(data));
    });

});
Let's also add some error handling,
just in case...
const https = require('https');
const URL = 'https://api.chucknorris.io/jokes/random';

https.get( URL, (response) => {

    ...

}).on("error", (err) => {

    console.log("Error:" + err.message);

});                                    
Available Builtin Modules
W3Schools List
List by @sindresorhus
NPM Node Package Manager

The official package manager for Node and is bundled & installed automatically with the environment.

$ npm --version
Let's see what npm can do:
  • npm install package-name
    const package = require('package-name');
  • npm init
    npm init -y
    package.json
  • npm install package-name --save
    npm install package-name --save-dev
  • .gitignore
package.json

A file that serves as documentation
for what packages your project depends on.

Allows you to specify the versions of a package that your project can use using semantic versioning rules.

$ npm install lodash@4.17.4

Makes your build reproducible which means that its way easier to share with other developers.

Quick mention: NPM scripts
Node.JS Packages: Hands-on
Pluralize
$ npm install pluralize --save

const pluralize = require('pluralize');

let result = pluralize('test');
console.log( "test: ", result );

result = pluralize('paper');
console.log( "paper: ", result );

result = pluralize('mummy');
console.log( "mummy: ", result );
Colors
$ npm install colors --save

require('colors');

console.log('hello'.green); // outputs green text
console.log('i like cake and pies'.underline.red) // outputs red underlined text
console.log('inverse the color'.inverse); // inverses the color
console.log('OMG Rainbows!'.rainbow); // rainbow
Convert-Units
$ npm install convert-units --save

const convert = require('convert-units');

// Days to Hours
let result = convert(1).from('d').to('h');
console.log( result );

// Week(s) to Days
result = convert(1).from('week').to('d');
console.log( result );

// Kilobytes to MBytes
result = convert(1024).from('Kb').to('Mb');
console.log( result );

Putting it all together

require('colors');
const pluralize = require('pluralize');
const convert = require('convert-units');

let MB = convert(1024).from('Kb').to('Mb');
let output = MB + " " + pluralize('megabyte', MB);

console.log( output.red );
Our first Server App!

Go to: https://nodejs.org

DOCS > GUIDES > GETTING STARTED

Getting Started

Developing (like a boss)
with Nodemon

Nodemon Package

Once you have installed Node, let's try building our first web server.
Create a file named "app.js", and paste the following code:

const http = require('http');
const port = 3000;
const server = http.createServer((request, response) => {
    response.statusCode = 200;
    response.setHeader('Content-Type', 'text/plain');
    response.end('Hello World\n');
});

server.listen(port, () => {
    console.log(`Server running at port: ${port}`);
});

After that, run your web server using node app.js, visit http://localhost:3000
and you will see a message 'Hello World'

More on Node.JS HTTP(S) Handling
Anatomy of an HTTP Transaction
Combining HTTP Server
and NPM Modules

...to create our first Web Service!

Step 01
const http = require('http');
const port = 8080;
const server = http.createServer((request, response) => {
    response.statusCode = 200;
    response.setHeader('Content-Type', 'text/html');
    response.end("
Pluralize Web Service"); }); server.listen(port, () => { console.log(`Server running at port: ${port}`); });

Open https://localhost:8080 and check...

Step 02

Add two more modules to our app.js file

// Parse URLs
const url = require('url'); 

// Lets Pluralize!
const pluralize = require('pluralize');

You will need npm install pluralize for the 2nd module...

Step 03

Add some more code inside the request handler function:

const server = http.createServer((request, response) => {
    // url.parse( urlString, queryString Object)
    let parts = url.parse(request.url, true);
    let query = parts.query;
    console.log( query );

    ...

    if ( query.word ){
        response.write(pluralize(query.word));
    }
    response.end();
Opening our App
to the World via NGROK

Public URLs for demoing from your machine

https://ngrok.com/
Quick Setup

1) Go to https://ngrok.com/
and click on Get started for free

2) You will need to sign up first.
Try GitHub login for quick easy access

3) Follow the 4-step Setup & Installation guide

4) Copy the ngrok file to your app's folder
and run your app on port 8080

$ ./ngrok http 8080
Hands-on

Create your own tiny server
and share your content with the world!

...or Slack ;)

Deploying our Node.JS app
to the cloud
HEROKU

RESOURCES