Desarrollo Web Avanzado con Node.js

Licencia de Creative Commons mario@mariogl.com

Temario

Desarrollo web avanzado con Node.js

  • Características de Node.js y diferencias entre código bloqueante y no bloqueante
  • Lectura de archivos y emisión de peticiones
  • Trabajo en tiempo real con Node.js
  • Retos a resolver mediante esta tecnología
  • Emisores de eventos, requests, y escuchas
  • Streams: problemas a resolver
  • Escritura, lectura, piping y solución de la concurrencia
  • Exportación, instalación de NPM, dependencias, y versiones semánticas.
  • Rutas, disposición visual, construcción de URL y servidores express
  • Socket.io: la librería de sockets
  • Escucha, emisión, respuesta a peticiones y almacenamiento de datos del cliente
  • Persistencia de información
  • Redis, trabajo con listas, persistencia, emisión, y otros aspectos

Conceptos iniciales

Desarrollo web avanzado con Node.js

Conceptos iniciales

  • ¿Qué es Node.js?

  • ¿Para qué se usa?

  • ECMAScript 6

  • Módulos JS

  • npm

  • Código bloqueante y código no bloqueante

Desarrollo web avanzado con Node.js

Entorno de desarrollo

Desarrollo web avanzado con Node.js

Entorno de desarrollo

Desarrollo web avanzado con Node.js

Git

Desarrollo web avanzado con Node.js

Git - comandos básicos para el curso

  • Clonar un repositorio:

        git clone URL
     

  • Descargar última versión del repositorio:

        git pull origin master

Desarrollo web avanzado con Node.js

Git - configuración proxy

git config --global http.proxy http://username:password@host:port

git config --global https.proxy http://username:password@host:port

Desarrollo web avanzado con Node.js

Node.js y npm

Desarrollo web avanzado con Node.js

npm

  • Instalar última versión después de instalar Node.js
    (configurar proxy si es necesario): npm install -g npm

  • Repositorio de módulos distribuibles

  • Módulos globales y módulos locales

  • La carpeta node_modules

  • El archivo package.json:

    • npm init

    • Registro de dependencias

    • Dependencias de desarrollo y de producción

    • Versiones (SEMVER)

    • scripts

Desarrollo web avanzado con Node.js

npm - comandos

  • Instalar un paquete globalmente:
        npm install -g paquete

  • Instalar un paquete de producción:
        npm install paquete

  • Instalar un paquete de desarrollo:
        npm install paquete --save-dev

  • Instalar todas las dependencias:
        npm install

  • Instalar las dependencias de producción:
        npm install --production

  • Listar paquetes instalados:

        npm list --depth=0        (locales)
        npm list -g --depth=0   (globales)

Desarrollo web avanzado con Node.js

npm - configuración proxy

npm config set proxy http://username:password@host:port

npm config set https-proxy http://username:password@host:port

Desarrollo web avanzado con Node.js

JavaScript

 

Desarrollo web avanzado con Node.js

ES6

Desarrollo web avanzado con Node.js

  • let y const

let a = 3;

let a = 10;  // Error
var a = 12;  // Error

const b = 10;

b = 3; // Error

const obj = {
    x: 10,
    y: 12
}

obj.x = 15;  // OK

obj = {    // Error
    x: 15,
    y: 12
}

ES6

Desarrollo web avanzado con Node.js

  • let y const

  • Template literals

let nombre = "Antonio";

let cuadrado = function(x) {
    return x * x;
}

let n = Math.floor(Math.random() * 10);

let saludo1 = "Hola, " + nombre + ". El cuadrado de " + n + " es " + cuadrado(n) + ".";
let saludo2 = `Hola, ${nombre}. El cuadrado de ${n} es ${cuadrado(n)}.`;

ES6

Desarrollo web avanzado con Node.js

  • let y const

  • Template literals

  • for ... of

let nombres = ["Patricia", "Zacarías", "Miguel", "Maite"];

for (let i in nombres) {
    console.log(nombres[i]);
}

for (let nombre of nombres) {
    console.log(nombre);
}

let obj = {
    x: 3,
    y: 4
}

for (let i in obj) {
    console.log(obj[i]);
}

let nombre = "Antonio Jesús";

for (let c of nombre) {
    console.log(c);
}

ES6

Desarrollo web avanzado con Node.js

  • let y const

  • Template literals

  • for ... of

  • Funciones

    • Parámetros por defecto

function potencia(x, y = 2) {
    return Math.pow(x, y);
}

console.log(`10 elevado a 8 es ${potencia(10, 8)}`);
console.log(`El cuadrado de 5 es ${potencia(5)}`);

ES6

Desarrollo web avanzado con Node.js

  • let y const

  • Template literals

  • for ... of

  • Funciones

    • Parámetros por defecto

    • Función arrow:

      (parámetros) => expresión_devuelta;
const potencia = function (x, y = 2) {
    return Math.pow(x, y);
}

const potencia = (x, y = 2) => Math.pow(x, y);

setTimeout(() => console.log("pausa"), 2000);

ES6

Desarrollo web avanzado con Node.js

  • Operador spread

    • Parámetros en funciones

    • Enviar varios parámetros a partir de un array

    • push y unshift

    • Intercalar un array dentro de otro

    • Copiar un array en otro

// function(a, b, c)
let nums = [1, 3, 6];
function sumar(a, b, c) {
  console.log(a + b + c);
}
sumar(...nums);

// function(n parámetros)
let a = 3;
let b = 7;
let c = 8;

function sumar(...nums) {
  let suma = 0;
  for (n of nums) {
    suma += n;
  }
  console.log("La suma es " + suma);
}
sumar(a, b, c);

// push y unshift
let nums1 = [1, 3, 6];
let nums2 = [0, 52, 15, 9];

nums1.push(...nums2);
console.log(nums1);
nums1.unshift(...nums2);
console.log(nums1);

// meter un array en medio de otra
let nums1 = [1, 3, 6];
let nums2 = [0, 52, 15, 9];
nums1.splice(1, 0, ...nums2);
console.log(nums1);

// copiar un array
let nums1 = [1, 3, 6];
let nums2 = [...nums1];

Programación funcional con arrays

Desarrollo web avanzado con Node.js

  • Métodos:

    • map

let nombres = ["juan", "luisa", "amparo", "arturo"];

nombres = nombres.map(nombre => nombre.toUpperCase());

console.log(nombres);

Programación funcional con arrays

Desarrollo web avanzado con Node.js

  • Métodos:

    • map

    • filter

let personas = [
    {
        nombre: "juan",
        edad: 15
    },
    {
        nombre: "luisa",
        edad: 35
    },
    {
        nombre: "amparo",
        edad: 17
    },
    {
        nombre: "arturo",
        edad: 32
    }
];

let mayoresEdad = personas.filter(persona => persona.edad >= 18);

console.log(mayoresEdad);

Programación funcional con arrays

Desarrollo web avanzado con Node.js

  • Métodos:

    • map

    • filter

    • reduce

let nums = [2, 4, 10, 15, 12];

let suma = nums.reduce((x, y) => x + y);

let objs = [
    {
        x: 3,
        y: 2
    },
    {
        x: 8,
        y: 10
    },
    {
        x: 10,
        y: 15
    }
]

let sumaX = objs.reduce((x, o2) => x + o2.x, 0);            // Método 1
let sumaX = objs.map(o => o.x).reduce((x, y) => x + y);     // Método 2

Programación funcional con arrays

Desarrollo web avanzado con Node.js

  • Métodos:

    • map

    • filter

    • reduce

    • find

  • Encadenamiento

let notas = [
    {
        nombre: "juan",
        nota: 6
    },
    {
        nombre: "luisa",
        nota: 8
    },
    {
        nombre: "amparo",
        nota: 4
    },
    {
        nombre: "arturo",
        nota: 3
    }
];

let notasAprobados = notas.filter(n => n.nota >= 5).map(n => n.nota);

console.log(notasAprobados);

Módulos

Desarrollo web avanzado con Node.js

Módulos

Desarrollo web avanzado con Node.js

  • Importar: require()

  • Exportar: module.exports

  • Módulos del core

  • Módulos de terceros

  • Módulos locales

Asincronía

Desarrollo web avanzado con Node.js

Asincronía

Desarrollo web avanzado con Node.js

  • Callbacks

  • El patrón callback(err, ...)

  • Promesas:

    • then()

    • catch()

  • async/await

Entornos

Desarrollo web avanzado con Node.js

Entornos

Desarrollo web avanzado con Node.js

  • La variable de entorno NODE_ENV

  • Pasar la variable en package.json

  • Recoger la variable con process.env

  • Configuración por entornos

Utilidades

Desarrollo web avanzado con Node.js

Utilidades

Desarrollo web avanzado con Node.js

  • nodemon

  • chalk

  • debug

  • commander

  • inquirer

Utilidades - chalk

Desarrollo web avanzado con Node.js

const chalk = require('chalk');

console.log(chalk.red('Error'));
console.log(chalk.blue('Todo bien'));

Utilidades - debug

Desarrollo web avanzado con Node.js

const debug = require('debug')('pruebas');

debug('Hola');


// package.json:

scripts: {
    start: "SET DEBUG:pruebas && node index.js"
}

Utilidades - commander

Desarrollo web avanzado con Node.js

const program = require('commander');

program
    .option('-s --saluda', 'Emite saludo')
    .option('-t --texto [txt]', 'Texto')
    .parse(process.argv);

if (program.saluda) {
    if (program.texto) {
        console.log(program.texto);
    } else {
        console.log("¡Hola!");
    }
}

Utilidades - inquirer

Desarrollo web avanzado con Node.js

const inquirer = require('inquirer');

const prompt = inquirer.createPromptModule();

prompt([
    {
        type: 'confirm',
        name: 'mayor',
        message: '¿Estás en edad de trabajar?'
    },
    {
        type: 'list',
        name: 'profesion',
        message: '¿Cuál es tu profesión?',
        default: 0,
        choices: [
            {
                name: 'Programador',
                value: 'programador'
            },
            {
                name: 'Cualquier otra',
                value: 'otra'
            },
            {
                name: 'Ninguna',
                value: 'ninguna'
            }
        ],
        when: respuestas => respuestas.mayor
    }]).then(resp => {
        //


    });

Peticiones HTTP

Desarrollo web avanzado con Node.js

Peticiones HTTP - cliente

Desarrollo web avanzado con Node.js

  • El paquete axios

  • Promesas

const axios = require('axios');

axios.get(URL).then(resp => {
    console.log(resp.data);
});

axios.post(URL, datos).then(resp => {
    console.log(resp.data);
});

Peticiones HTTP - servidor

Desarrollo web avanzado con Node.js

  • El módulo http

  • Express.js

  • Middlewares:

    • morgan

    • body-parser

    • Propios

    • Gestor de errores

  • Rutas

Bases de datos

Desarrollo web avanzado con Node.js

Bases de datos

Desarrollo web avanzado con Node.js

  • Drivers directos

  • ORM

  • Sequelize

const Sequelize = require('sequelize');

const sequelize = new Sequelize('ciudades', 'user', 'pwd',
    {
        host: 'localhost',
        dialect: 'mysql',
        operatorsAliases: false,
        logging: s => console.log("DB: ", s),
        dialectOptions: { decimalNumbers: true }
    });

sequelize.authenticate().then(() => {
    console.log("Conectado a MySQL");
}).catch(err => {
    console.error("No se ha podido conectar a MySQL: " + err.message);
})

Bases de datos - Sequelize

Desarrollo web avanzado con Node.js

  • Definición del modelo

let Ciudades = sequelize.define('ciudades', {
    nombre: {
        type: Sequelize.STRING
    },
    tieneAyuntamiento: {
        type: Sequelize.BOOLEAN,
        allowNull: false
    }
}, {
        freezeTableName: true,
        timestamps: false
    }
);

Bases de datos - Sequelize

Desarrollo web avanzado con Node.js

  • Operaciones con el modelo

Ciudades.findAll({ attributes: ['nombre'] })
    .then(data => console.log(data));
Ciudades.findById(10)
    .then(data => console.log(data));
Ciudades.create({ nombre: 'Zaragoza', tieneAyuntamiento: true })
    .then(respuesta => console.log(respuesta));
Ciudades.update({ nombre: 'Zaragoza2' }, { where: 10 })
    .then(respuesta => console.log(respuesta));
Ciudades.update({ nombre: 'Zaragoza3' }, { returning: true, where: 10 })
    .then(respuesta => console.log(respuesta));
Ciudades.destroy({ where: { nombre: 'Zaragoza3' } })
.then(respuesta => console.log(respuesta));

Redis

Desarrollo web avanzado con Node.js

Redis

Desarrollo web avanzado con Node.js

  • Base de datos NoSQL

  • Muy rápida

  • Pares clave/valor

  • El módulo redis

const redis = require('redis');

const redisClient = redis.createClient('URL');
redisClient.auth('pwd');

redisClient.on('connect', () => {
    console.log("Conectado a Redis");
}).on('error', err => {
    console.error("No se pudo conectar a Redis: ", err.message);
});

Redis

Desarrollo web avanzado con Node.js

redis.hgetall('nombre', (err, datos) => {
    console.log(datos);
});
redis.hmset('nombre', 'key2', 'valor1', 'key2', 'valor2');

Servidor web

Desarrollo web avanzado con Node.js

Servidor web

Desarrollo web avanzado con Node.js

  • Express

  • Plantillas: Handlebars

  • Configurar Express para que use Handlebars como motor de plantillas

const path = require('path');
const http = require('http');
const express = require('express');
const hbs = require('express-handlebars');

const app = express();
const server = http.createServer(app);

app.engine('hbs', hbs());
app.set('view engine', 'hbs');
app.set('views', path.resolve(__dirname, 'vistas'));
app.use(express.static(path.resolve(__dirname, 'public')));

app.get('/', (req, res) => {
    res.render('index', { dato1: valor1, dato2: valor2 });
});

server.listen(8080, () => {
    console.log("Servidor corriendo");
});

Vista Handlebars

Desarrollo web avanzado con Node.js

<!DOCTYPE html>
<html lang="es">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Prueba</title>
</head>

<body>
    <p>Mostrando dato 1: {{dato1}}</p>
    <p>Mostrando dato 2: {{dato2}}</p>
</body>

</html>

Sockets

Desarrollo web avanzado con Node.js

Sockets

Desarrollo web avanzado con Node.js

  • El módulo socket.io

  • Servidor y cliente

Sockets - servidor

Desarrollo web avanzado con Node.js

const http = require('http');
const express = require('express');

const app = express();
const server = http.createServer(app);
const io = require('socket.io')(server);

io.on('connection', socket => {
    console.log("Usuario conectado");
    socket.on("disconnect", () => {
        console.log("Usuario desconectado");
    })
    socket.on("evento", datos => {
        socket.broadcast.emit("evento2", datos2);
    });

    setTimeout(() => {
        io.emit('evento3', dato3);
    }, 2000);
});

Sockets - cliente

Desarrollo web avanzado con Node.js

<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Sockets</title>
    <script src="/socket.io/socket.io.js"></script>
    <script src="scripts.js" defer></script>
</head>
// JS

let socket = io();

socket.on('evento', datos => console.log(datos));

socket.emit('evento2', datos2);

Links

Desarrollo web avanzado con Node.js

Desarrollo web avanzado con Node.js