Node.js Workshop

Session 1 - 19/01/2016

What is Node.js?

Node.js® is a JavaScript runtime built on Chrome's V8 JavaScript engine. Node.js uses an event-driven, non-blocking I/O model that makes it lightweight and efficient. Node.js' package ecosystem, npm, is the largest ecosystem of open source libraries in the world.
Note: V8 compiles Javascript into machine code on the fly

What is Node.js?

Asynchronous and Event Driven

All APIs of Node.js library are asynchronous that is, non-blocking. There is no sleep on Node.

What is Node.js?

Very Fast

Being built on Google Chrome's V8 JavaScript Engine, Node.js library is very fast in code execution.
Node vs PHP

What is Node.js?

Single Threaded but Highly Scalable

Node.js uses a single threaded model with event looping.

A bit of history

What else can it do?

Fire up your machines!

http://bit.ly/nodejs-ws

Before we start: ES6


const something = 'my value';
//We are saying we're not going to assign this variable ever again

let other = 'my value';
//We can reassign this one, the variable only exists on the current block

//insted of
var myfunction = function(argument) {
	//do something;
	return something;
}
//We do
const myfunction = (argument) => {
	//do something;
	return something;
}
//If our function only has one line
//insted of
var myquickfunction = function(argument) {
	return console.log(argunment);
}
//We do
const myquickfunction = (argument) => console.log(argument);

//String composition
//instead of
var phrase = 'First part ' + secondPart;
//We do
let phrase = `First part ${secondPart}`;

Getting ready

Sometimes getting and switching between different Node.js versions can be a pain, NVM (Node Version Manager) solves that.

Install nvm (https://github.com/creationix/nvm)


						$ curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.30.2/install.sh | bash
					

If you're on Windows you may want to follow this: https://github.com/coreybutler/nvm-windows

Getting ready

We're going to use the latest stable release of Node.js and set it as default:


$ nvm install stable
...
$ nvm alias default stable
$ nvm use default
$ node -v
v5.6.0
Note: Node always comes with npm (Node Package Manager).

Getting ready

Node is a REPL interactive shell by default:


$ node
> var a = [1, 2, 3];
undefined
> a[1]
2
> var fs = require('fs');
undefined
> fs.readdir('.', (err, files) => console.log(files));
undefined
> [ 'app.js', 'node_modules', 'package.json' ]
Note: Press cntrl+C to exit the shell

Starting up

Lets start by creating the project folder and initializing it.


$ mkdir nodejs-project
$ cd nodejs-project
$ npm init
name: (nodejs-project)
version: (1.0.0) 0.0.1
description: My awesome Node.js project
entry point: (index.js) app.js
test command:
git repository:
keywords:
author: Your name <your@email.com>
license: (ISC)
About to write to /nodejs-project/package.json:
{
  "name": "nodejs-project",
  "version": "0.0.1",
  "description": "My awesome Node.js project",
  "main": "app.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "Your name <your@email.com>",
  "license": "ISC"
}
Is this ok? (yes) yes

Starting up

Let's add some of the dependencies we'll be using:


$ npm install express --save
$ npm install nodemon --save-dev

Now check your package.json

Exercise 1: Promises

The Promise object is used for deferred and asynchronous computations. A Promise represents an operation that hasn't completed yet, but is expected in the future.

Exercise 1: Promises

What problem does it solve? The single-threaded, non blocking part.


//app.js
'use strict';

const asyncStuff = () => {
	let value = null;
	setTimeout(() => { value = `I'm done!` }, 100);
	return value;
};

console.log(asyncStuff());
//null
Run it like this:
node app.js

Exercise 1: Promises

We could solve it with callbacks


//app.js
'use strict';

const asyncStuff = (callback) => {
  let value = null;
  setTimeout(() => {
    value = `I'm done!`
    callback(value);
  }, 100);
};

asyncStuff((value) => console.log(value));

But...

Exercise 1: Promises

The christmas tree of callbacks (we don't want that!)


asyncStuff1(function(err, result) {
  asyncStuff2(function(err, result) {
    asyncStuff3(function(err, result) {
      asyncStuff4(function(err, result) {
        asyncStuff5(function(err, result) {
          // do something useful
        })
      })
    })
  })
})

Exercise 1: Promises

F*c$ callbacks, use Promises!


'use strict';

const asyncStuff = () => {
	return new Promise((resolve, reject) => {
		setTimeout(() => {
			resolve(`I'm done!`);
		}, 100);
	});
};

asyncStuff()
.then((result) => console.log(result));
//I'm done!

Exercise 1: Promises

You can chain them!


...
const asyncStuff2 = (response1) => {
	return new Promise((resolve, reject) => {
		setTimeout(() => {
			resolve(`${response1} Twice!`);
		}, 100);
	});
};

asyncStuff()
.then(asyncStuff2)
.then((result) => console.log(result));
//I'm done! Twice!

Exercise 1: Promises

Catch the rejections!


...
const asyncStuff2 = (response1) => {
	return new Promise((resolve, reject) => {
		setTimeout(() => {
			reject(new Error('Something went wrong'));
		}, 100);
	});
};

asyncStuff()
.then(asyncStuff2)
.then((result) => console.log(result))
.catch((error) => console.error('Promise failed', error));
//Promise failed [Error: Something went wrong]

Exercise 2: NPM scripts

You can automate, build and do lots of things with npm scripts. Most of the time you don't need grunt or gulp.
start and test are supported out of the box, otherwise you need to run npm run-script [scriptname].


//package.json
...
"scripts": {
	"start": "nodemon -e js -w ./ ./app.js"
}
...
Now run:
npm start

Exercise 2: NPM scripts

You can use script hooks to execute things before and after your scripts


//package.json
...
"scripts": {
  "start": "nodemon -e js -w ./ ./app.js",
  "prestart": "echo '---- Watching app.js file ----'"
}
...
Now run:
npm start
Learn more about script hooks here
Note: One of the most useful hooks is the postinstall one.

Exercise 3: CommonJS modules

One of the big advantages of Node.js is that everything can be a module.


//config/env/development.js
module.exports = {
	PORT: 8000
};

//config/index.js
'use strict';

module.exports = (() => {
  const env = process.env.NODE_ENV || 'development';

  console.info( 'Environment: ' + env );

  try {
    return require('./env/' + env );
  } catch (ex) {
    console.error('Environment not recognised, exiting');
    process.exit(1);
  }
})();
Find other ways to use "export" here

Exercise 3: CommonJS modules

You can get a local module using require with a relative path.


//app.js
'use strict';

const config = require('./config');

console.log(config);
Run it with
node app.js

What happens if you set the env variable?
export NODE_ENV=production && node app.js

Let's create a server!

Creating a server is super easy using Express.


//app.js
'use strict';

const config  = require('./config'),
      express = require('express'),
      app     = express();

app.get('/', (req, res) => {
  res.send('Hello World!');
});

app.listen(config.PORT, () => {
  console.log(`Server listening on localhost:${config.PORT}`);
});
//Server listening on localhost:3000
Go check it out! http://localhost:3000/

Let's create a WEB server!

Let's begin with creating some folders and empty files


.
├── app.js
├── config
│   ├── env
│   │   └── development.js
│   └── index.js
├── package.json
├── public
│   ├── css
│   │   └── main.css
│   ├── img
│   └── js
│       └── main.js
└── views
    └── index.ejs

Let's create a WEB server!

We'll be using EJS for the view templates, but we could use Moustache, Jade, or any other.


$ npm i ejs --save

//views/index.ejs
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8"> <title>My Project</title>
		<link rel="stylesheet" href="/css/main.css" media="screen" title="no title" charset="utf-8">
	</head>
	<body>
		<h1><%=message%></h1>
		<script src="/js/main.js" charset="utf-8"></script>
	</body>
</html>

Let's create a WEB server!

Now lets make our server serve static content and render views.


//app.js
...

app.use(express.static('public'));

app.set('view engine', 'ejs');

app.get('/', (req, res) => {
  res.render('index', {message: 'Hello World'});
});

app.listen(config.PORT, () => {
  console.log(`Server listening on localhost:${config.PORT}`);
});
Go check it out! http://localhost:3000/

Let's create a WEB server!

We could also create partials to use in different pages.


views
├── index.ejs
└── partials
    ├── footer.ejs
    └── header.ejs

//views/index.ejs
<%- include('partials/header') -%>
	<h1><%=message%></h1>
<%- include('partials/footer') -%>

What we learned today

  • Node.js: What is it, how it works, how to use it.
  • Promises: When and how to use them.
  • NPM: How to install packages and run scripts.
  • CommonJS: How to define modules.
  • Express: How to create a web server and render with EJS.

Thank you!

Check out the repo https://github.com/martip-sainsburys/nodejs-workshop.
What else do you want to learn?