IMPORTANT: Per accedir als fitxer de subversion: http://acacha.org/svn (sense password). Poc a poc s'aniran migrant els enllaços. Encara però funciona el subversion de la farga però no se sap fins quan... (usuari: prova i la paraula de pas 123456)

https://carlosazaustre.es/blog/browserify-desarrollando-tu-frontend-como-en-node-js/

Node.js® (aka Node) és un runtime de JavaScript construït utilitzant el Chrome's V8 JavaScript engine. Node.js utilitza un model event-driven, non-blocking I/O que el fa ser molt lleuger i eficient.

El ecosistema de paquets de node és npm un dels repositoris de paquets open source més gran del mon.

Introducció

Node.js és un entorn JavaScript pensat per executar-se al costat del servidor que utilitza un model asíncron (vegeu programació asíncrona) i dirigit per esdeveniments (event-driven).

Node utilitza JavaScript V8 de Google. V8 és una màquina virtual molt ràpida i de molta qualitat (escrita per gent com Lars Bak).

Node suporta els protocols TCP, DNS i HTTP.

Recursos:

Història

Node.js va ser creat per Ryan Dahl i altres desenvolupadors que treballaven a Joyent al 2009. La primera versió va ser publicada per a Linux el mateix 2009 i el seu desenvolupament i manteniment va ser liderat per Dahl i esponsoritzat per Joyent on treballava Ryan Dahl.

Al 2011 es va incorporar npm un gestor de paquets/paquet manager per a Node.js més tard al 2012 el creador de npm Isaac Schlueter portaria el lideratge del projecte i és actual CEO de Node.js. Npm facilita la instal·lació, actualització i desinstal·lació de llibreries/mòduls Node.js

Al 2011 es va crear una implementació nativa per a Windows.

Al 2012 Ryan Dahl va deixar el lideratge del projecte i el va passar al creador de npm Isaac Schlueter i al 2014 Schlueter va anunciar que Timothy J. Fontaine seria el nou líder del projecte.

Al desembre 2014 es va crear un fork de Node.js anomenat io.js. Es va crear per culpa de discrepàncies amb la governança del projecte per part de Joyent

Al febrer de 2015 es ca crear la Node.js Foundation i tan Node.js com io.js]] i decideixen participar-hi.

Resources:

Característiques tècniques

Node.js permet la creació de eines de servidor com web servers i altres networking tools utilitzant Javascript com a llenguatge de programació bàsic però amb el suport d'una col·lecció de mòduls per tal de gestionar funcionalitat comuna/habitual com la gestió de fitxers i altres operacions I/O, networking ( amb suport per HTTP, TCP, UDP, DNS, or TLS/SSL), buffers, cryptography, streams, i moltes altres funcionalitats core. Totes aquestes funcionalitat estan creades/dissenyades per reduir la complexitat de programar aplicacions de servidor i/o networking (vegeu el curs Programació_en_xarxes per comparar amb exemples de programació amb C o Java)

Node.js esta pensat principalment per crear aplicacions de xarxa a la part de servidor com altres llenguatges com PHP o Python però de la mateixa forma que amb PHP es poden fer programes de client o CLI igual passa amb Node.js (de fet s'ha estes bastant l'ús a la part de client gràcies a eines com Browserify). La principal diferència entre PHP i Node.js és que node és un llenguatge no bloquejant (non-blocking I/O)

Node.js implementa una programació orientada a esdeveniments (event-driven programming) sense la necessitat d'utilitzar Threads. S'utilitza un model de programació inherentment orientat a esdeveniments utilitzant callbacks i signal completion implementant una solució per a la Programació concurrent utilitzant JavaScript per a Unix network programming.

Milers de llibreries Open Source s'han creat per a Node.js en els últimes temps i són fàcilment distribuïbles utilitzant npm

Instal·lació

Manual

$ cd
$ wget https://nodejs.org/dist/v4.2.3/node-v4.2.3-linux-x64.tar.gz
$ tar xvzf node-v4.2.3-linux-x64.tar.gz
$ editor .bashrc

i afegir:

export PATH=~/node-v4.2.3-linux-x64/bin:${PATH}

Comproveu:

$ bash
$ which npm
/home/sergi/node-v4.2.3-linux-x64/bin/npm
$ which node
/home/sergi/node-v4.2.3-linux-x64/bin/node
$ npm -v
2.14.7
$ node -v
v4.2.3

Compilar codi font

Aneu a la web:

https://nodejs.org/en/download/

IMPORTANT: L'exemple utilitzar el codi font per tan baixeu-vos la opció Source Code

El fitxer en el moment d'escriure aquest tutorial (--acacha (discussió) 21:17, 18 març 2014 (CET)) és:

$ wget http://nodejs.org/dist/v0.10.26/node-v0.10.26.tar.gz

Descomprimiu:

$ tar xvzf node-v0.10.26.tar.gz

Abans instal·leu:

$ sudo apt-get update
$ sudo apt-get install build-essential -y
$ sudo apt-get install python libssl-dev -y

Heu d'escollir lloc on instal·lar, per exemple:

/usr/share/nodejs

Per exemple:

$ sudo cp -r node-v0.10.26 /usr/share/nodejs
$ cd /usr/share/nodejs

Ara els típics tres passos instal·lació a mà:

$ sudo ./configure
$ sudo make
$ sudo make install

Ara teniu a:

$ ls /usr/local/bin
node  npm  phonegap
$ ls -la /usr/local/bin
total 10260
drwxr-xr-x  2 root root     4096 mar 18 21:42 .
drwxr-xr-x 11 root root     4096 abr 19  2013 ..
-rwxr-xr-x  1 root root 10478648 mar 18 21:29 node
lrwxrwxrwx  1 root root       38 mar 18 21:42 npm -> ../lib/node_modules/npm/bin/npm-cli.js

Els executables node, npm

NOTA: Phonegap apareix pq ja tenia instal·lat?

Recursos:

Repositoris

Require i mòduls

Llegiu també/abans Javascript Modules

La paraula reservada require s'utilitza conjuntament amb npm i els mòduls npm (carpeta node_modules) per gestionar les dependències.

Node.js té un sistema simple per crear mòduls i per carregar-los. A Node cada mòdul és un fitxer

Per exemple si ens trobem la línia:

var Vue = require('vue') 

o

var Vue = require('vue.js') 

ja que l'ús de l'extensió és opcional i aleshores podem iniciar un nou objecte de Vue amb:

 var vm = new Vue({
    el: '#app',
 ...

el que estem indicant a Node.js és una dependència, és a dir que la variable Vue serà per tal que no doni un error de Vue not found serà utilitzat el mòdul Vue. Això ens evita els "includes" de fitxer javascript de dependències.

També es pot fer localment per indicar una dependència:

 var hello = require(./alertHello)
 hello();

L'ús del punt indica l'ús en local i com a pas relatiu. En aquest cas però el fitxer ./alertHello ha d'incloure la definició d'un mòdul de Node.js:

 module.exports = function() {
  alert('Hello world!');
}

Com podeu veure s'utilitza module.exports on module és un objecte especial que gestiona els mòduls. També es possible executar directament el mòdul amb:

 var hello = require(./alertHello)()

Resources:

Core modules

NodeJS porta de sèrie compilats una sèrie de mòduls bàsics/core anomenats core modules (es guarden a la carpeta lib de NodeJS). Aquests mòduls no cal carregar-los amb npm ni amb cap carrega local de fitxer. Llista dels core modules més importants:

Consulteu l'API: https://nodejs.org/api

Resources:

File modules

Els mòduls també es poden trobar a fitxers bàsicament de 3 tipus/extensions:

  • .js: Javascript text files
  • .json': JSON files
  • '.node': són interpretats com compiled addon modules i carregats utilitzats dlopen

Si al fer un require s'indica la extensió aleshores s'utilitza aquella extensió sinó es prova de buscar primer un fitxer .js, després un .json i sinó un .node. Sino es troba cap fitxer aleshores succeeix un error MODULE_NOT_FOUND.

Això si el path per indicar un mòdul de fitxer ha de començar per / o ./

/: path absolut. Exemple: require('/home/marco/foo.js') carregarà el fitxer /home/marco/foo.js.
  • ./ o ../': path relatiu al fitxer que executa require. Exemple: require('./circle') utilitzarà el fitxer circle.js si existeix i sinó provarà amb circle.json o circle.node

IMPORTANT: Sense el prefix '/', './', or '../' aleshores vol dir que s'utilitzarà la carpeta node_modules o un core module. Llegiu el següent apartat per a més informació.

Carpeta node_modules

Si el nom del mòdul passat al mètode:

require

no és un core module (aka native module) i no començar per '/', '../', o './' aleshores comença un procediment per trobar el mòdul que bàsicament consisteix en buscar carpetes node_modules des del cami on s'ha demanat el require fins arribar a la arrel del sistema. Un exemple:

Si un fitxer a:

/home/ry/projects/foo.js

crida a:

require('bar.js')

Node buscarà el mòdul a les següents localitzacions:

/home/ry/projects/node_modules/bar.js
/home/ry/node_modules/bar.js
/home/node_modules/bar.js
/node_modules/bar.js

Vegeu també npm install ([1])

Resources:

Objecte module

Mòduls. Creació de mòduls. module.exports

Nodejs module system és el sistema que té node.js per estructurar el codi en mòduls. Veiem un exemple:

var hello = require('./hello');
hello.world();

Fitxer 'hello.js':

exports.world = function() {
  console.log('Hello World');
}

Proveu amb:

$ node main.js
Hello World

Alternativa:

module.exports = function() {
  // ...
}


Veiem un altre exemple definint múltiples mètodes a exportar a el mateix objecte:

'use strict';

var logDate = function() {
  console.log(new Date().getDate());
}

var logMonth() {
    console.log(new Date().getMonth());
}

exports.logDate = logDate;
exports.logMonth = logMonth;

I és pot utilitzar amb:


var dateUtils = require('./dateutils');
dateUtils.logDate();
dateUtils.logMonth();

Resources:

Global scope

A Node existeixen objectes globals, és a dir objectes que existeixen per defecte a Node.js sense necessitat d'importar cap mòdul o llibreria de tercers. Recordeu que a Javascript passa el mateix (per exemple disposem d'objecte com Math). De fet als navegador hi ha un objecte global per defecte que és Window i que és a on totes les variables són assignades:

var variable = "Prova"
console.log(Window.variable)

és assignada a l'objecte Window.

L'objecte global per defecte a Node és global però compte que a diferència de Javascript als navegadors les variables soltes no són automàticament afegides a l'scope Global sinó que són locals al fitxer (i recordeu que cada fitxer és un mòdul a Node). Per tant les variables a Node passen a ser per defecte locals al fitxer i no pas globals.

Vegeu també Javascript Scope

Exemples aplicacions

Servidor senzill. Hello world

http://howtonode.org/hello-node
$ cat > ~/server.js <<EOF
var http = require('http');
http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('Hello World\n');
}).listen(1337, '127.0.0.1');
console.log('Server running at http://127.0.0.1:1337/');

podeu executar el servidor amb la comanda:

$ node ~/server.js

I el podeu provar amb lynx:

$ sudo apt-get install lynx
$ lynx -dump http://127.0.0.1:1337/

O qualsevol navegador:

http://localhost:1337/

npm

Vegeu l'article npm

Conceptes. Node-isms

Aka node-isms

Event loop. process.nextTick()

Llegiu també:  Programació asíncrona amb Javascript

És important comprendre el concepte de event loop a Node.js. El primer que cal entendre (sobretot per aquells que vingueu de la programació concurrent de tota la vida) és que Node.js no utilitza Threads per a gestionar la programació concurrent o executar múltiples tasques en paral·lel. Realment Node.js executa un sol fil d'execució que s'encarrega de gestionar el que es coneix com event loop.

Per a crear codi asíncron s'utilitza el patró callback. Si s'ha d'executar una operació I/O que seria bloquejant (com un accés a fitxer o una petició de xarxa com HTTP) el que fem és establir un callback que serà el que s'executarà quan l'acció finalitzi (molt similar al que fem amb Ajax per exemple amb el patró promise). Això permet a node.js executar altre codi mentrestant espera a que finalitzi el procés bloquejant. Realment Node.js executa múltiples tasques en background però una sola tasca en foreground. Cada cop que una operació en background finalitza envia una senyal (anomenada signal code) per tal que s'executi el callback al thread foreground o thread principal.

Node depèn d'entre d'altres de la llibreria libuv que és la llibreria encarregada de gestionar la cua de processos amb esdeveniments asíncrons.

event-loop.png
  • Tots els callbacks programats utilitzant process.nextTick() són executats al final de fase de cada event loop abans de passar a la següent fase
  • '"Pending callbacks"': es la cua on es posen els callbacks

De fet un Event Loop no és res més que un loop amb pseudcodi similar a:

while(queue.waitForMessage()){
  queue.processNextMessage();
}

és a dir una cua de missatges que esta executant-se contínuament.

El procés de foreground o procés principal és el que executa de forma indefinida el event loop. Cada execució del eventloop és anomenat un tick. De fet node es com una CPU que només pot executar en cada tick un sol callback provinent dels processos en background. Per aquesta raó encara que tinguem un sistema multiprocesador en un moment concret de temps no executem mai en paral·lel dos callbacks al mateix temps, és a dir només podem estar processant un únic esdeveniment en un instant precís de temps.

NOTA: Aquesta és la raó per la que Node te gran rendiment amb operacions I/O, però no pas amb operacions intensives de CPU

Que fa doncs process.nextTick()? Vegem un exemple:

function foo() {
    console.error('foo');
}

process.nextTick(foo);
console.error('bar');

Això mostrarà:

bar 
foo

és a dir bar abans de foo tot i que en el codi estan ordenats al revés ja que posposem l'execució de foo per al següent tick del event loop de Node.

Amb Javascript pur es pot aconseguir el mateix efecte amb setTimeout() (vegeu Javascript event loop):

setTimeout(foo, 0);
console.log('bar');

Oco però que process.nextTick() és molt més eficient!

Resources:

__dirname

__filename

Frameworks

Express.js

Vegeu Express.js

Socket.io

Vegeu Socket.io

Connect

Vegeu Connect

GCM. Google Cloud Messaging

node-gcm

Vegeu node-gcm

Push servers

https://www.npmjs.org/package/node-pushserver

Multiplayer game development

Vegeu a l'article Game development un joc de tancs senzill amb Multiplayer: Game_development#Multiplayer

Troubleshooting. Resol·lució de problemes

Error: Module version mismatch. Expected 48, got 51.

O error similar. Normalment indica que una aplicació node.js requereix d'una versió específica de node.js i naltros tenim un altre versió. Es pot solucionar utilitzant nvm.

Podeu consultar la taula de versions a:

https://nodejs.org/en/download/releases/


Vegeu també

Enllaços externs