Tag Archives

8 Articles
Node.JS 4.0.0 vient de sortir

Node.JS 4.0.0 vient de sortir

Bonjour à tous,

Une semaine après la rentrée, une grande nouvelle a été annoncée hier soir : Node.JS 4.0.0 a été publiée en version finale.

4.0.0 ? Mais on était pas en 0.12 juste avant ?

Je vous répondrait par un grand oui. Ce changement brutal de version s’explique par le fait que Node.JS et IO.JS ont été mergés ensemble pour cette nouvelle version. Ce qui veut dire que nous avons le droit, pour cette version, à toutes les nouveautés de IO.JS 3.0 mais pas que. Voici le début du changelog fourni par Node.JS

  • child_process: ChildProcess.prototype.send() and process.send() operate asynchronously across all platforms so an optional callback parameter has been introduced that will be invoked once the message has been sent, i.e. .send(message[, sendHandle][, callback]) (Ben Noordhuis) #2620. node: Rename « io.js » code to « Node.js » (cjihrig) #2367.
  • node-gyp: This release bundles an updated version of node-gyp that works with all versions of Node.js and io.js including nightly and release candidate builds. From io.js v3 and Node.js v4 onward, it will only download a headers tarball when building addons rather than the entire source. (Rod Vagg) #2700 npm: Upgrade to version 2.14.2 from 2.13.3, includes a security update, see https://github.com/npm/npm/releases/tag/v2.14.2 for more details, (Kat Marchán) #2696. timers: Improved timer performance from porting the 0.12 implementation, plus minor fixes (Jeremiah Senkpiel) #2540, (Julien Gilli) nodejs/node-v0.x-archive#8751 nodejs/node-v0.x-archive#8905
  • util: The util.is*() functions have been deprecated, beginning with deprecation warnings in the documentation for this release, users are encouraged to seek more robust alternatives in the npm registry, (Sakthipriyan Vairamani) #2447.
  • v8: Upgrade to version 4.5.103.30 from 4.4.63.30 (Ali Ijaz Sheikh) #2632.
  • Implement new TypedArray prototype methods: copyWithin(), every(), fill(), filter(), find(), findIndex(), forEach(), indexOf(), join(), lastIndexOf(), map(), reduce(), reduceRight(), reverse(), slice(), some(), sort(). See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray for further information.
  • Implement new TypedArray.from() and TypedArray.of() functions. See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray for further information.
  • Implement arrow functions, see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions for further information.
  • Full ChangeLog available at https://github.com/v8/v8-git-mirror/blob/4.5.103/ChangeLog

Pour installer cette version, rien de plus simple :

# Using Ubuntu
curl -sL https://deb.nodesource.com/setup_4.x | sudo -E bash -
sudo apt-get install -y nodejs

# Using Debian, as root
curl -sL https://deb.nodesource.com/setup_4.x | bash -
apt-get install -y nodejs

Pensez aussi à réinstaller vos modules npm pour les compiler avec le nouveau moteur mais attention, il y a encore plusieurs modules non compatibles dont :

  • IconV
  • Canvas
  • ICU-charset-detector

Sources

Mise en production projet node.js

Mise en production projet node.js

Présentation

Après un temps d’abscence, me revoici pour vous présenter comment mettre en production votre projet Node.js au sein de votre serveur de production. Personnellement, j’utilise NGinx pour faire le lien avec le serveur http de node.JS.

Sachez que j’utilise un serveur Ubuntu x64 14.04 LTS pour cet article. Il se peut que selon votre distribution, certaines commandes changent.

Prérequis

Avant de commencer, sachez que je n’utilise pas les versions de node.js et de npm fournis par ubuntu car elles ne sont pas mise à jour régulièrement et que la mise à jour de npm par lui même ne marche pas, De même pour NGinx. De plus, pour gérer comme il faut mon projet Node.JS, j’utilise monit et upstart. Voici donc toutes les commandes à rentrer pour être prêt à commencer :

# avant de commencer, mettre à jour Ubuntu
sudo apt-get update && sudo apt-get upgrade
# installation de paquets nécessaires disponibles dans ubuntu
sudo apt-get install imagemagick libicu-dev libgd2-xpm-dev python-software-properties software-properties-common build-essential upstart monit
# installation de nginx et de node.js
sudo add-apt-repository ppa:nginx/stable
sudo add-apt-repository ppa:chris-lea/node.js
sudo apt-get update
sudo apt-get install nginx nodejs
Attention : Avec cette installation de Node.JS nous nous retrouvons en 0.10.X. De plus, la commande de base n’est pas node mais nodejs

Utilisateur webuser

De base, l’utilisateur exécutant la partie web chez moi ne doit pas avoir les accès sudo. Je créée donc un nouvel utilisateur avec pour nom webuser :

sudo useradd -d /home/webuser -m webuser
sudo passwd webuser
su webuser
# on est chez webuser
cd
mkdir public_html
exit

NGinx

Maintenant voici le fichier NGinx à créer pour pouvoir faire le lien entre le port 80 (ou 443 si vous passez via https) et votre processus node (les 3/4 du temps sur le port 3000). Le fichier sera à placer dans /etc/nginx/sites-available/

upstream app_nodenomunique {
        server 127.0.0.1:3000;
}

server {
    listen 443 ssl;
    server_name api.testnode.com;
    ssl_certificate /etc/nginx/certificates/site.crt;
    ssl_certificate_key /etc/nginx/certificates/site.key;
    ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers HIGH:!aNULL:!MD5;

    access_log /var/log/nginx/votreprojet.log;

    # supposedly prevents 502 bad gateway error;
    # ultimately not necessary in my case
    large_client_header_buffers 8 32k;

    client_max_body_size 10M;

    # pass the request to the node.js server with the correct headers and much more can be added, see nginx config options
    location / {
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_set_header X-NginX-Proxy true;

        # prevent 504
        proxy_read_timeout 600;

        # supposedly prevents 502 bad gateway error;
        # ultimately not necessary in my case
        proxy_buffers 8 32k;
        proxy_buffer_size 64k;

        proxy_pass http://app_nodenomunique/;
        proxy_redirect off;

        # the following is required as well for WebSockets
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

Comment ça marche exactement ici ? La liaison vers votre serveur node.JS est renseignée via cette partie du fichier :

upstream app_nodenomunique {
        server 127.0.0.1:3000;
}

Ensuite, nous indiquons dans la partie location /, qui correspond aux réglages de la racine de notre url (ici api.testnode.com) de passer par le proxy http://app_nodeunique/ qui correspond à notre redirection vers 127.0.0.1:3000. Pour l’utilisateur accédant à votre site, api, … c’est entièrement transparent.

Pour finir, vous devrez créer un lien symbolique pour placer le fichier dans le répertoire sites-enabled puis de relancer nginx :

sudo ln -s /etc/nginx/sites-available/api.testnode.com /etc/nginx/sites-enabled/
sudo service nginx restart
Si vous essayez d’accéder à votre site, vous devriez avoir, si bien entendu votre serveur node.JS est coupé, une erreur 502 voulant dire que Nginx ne peut réaliser la redirection.

Initialisation du projet depuis GIT

Cette partie vous concerne si vous avez votre projet hébergé chez git. Je donne ici les commandes à effectuer pour initialiser ce projet. De toute manière voici l’arborescence que vous devriez avoir :

/
˪ home
    ˪ webuser
        ˪ public_html
            ˪ votreprojet 

Et maintenant l’initialisation via git :

cd /home/webuser/public_html
sudo -u webuser -H git clone git@votreserveur:userougroupe/votreprojet.git
cd votreprojet
sudo -u webuser -H npm install

Upstart

Upstart va servir à démarrer notre serveur comme si c’étasit un service linux, avec le bon utilisateur comme propriétaire. Pour cela, vous devez créer le fichier /etc/init/votreprojet.conf avec le contenu suivant :

#/etc/init/votreprojet.conf
description "NodeServer init script"
author "throrin19"

start on startup # it's possible to use "net-device-up IFACE=eth0" for starting the process when the ethernet adapter is up
stop on shutdown

script
    cd /home/webuser/public_html/votreprojet
    exec sudo -u webuser NODE_ENV=production /usr/bin/nodejs /home/webuser/public_html/votreprojet/server.js >> /home/webuser/logs/nodeserver.log 2>&1
end script
Attention : Vous devrez impérativement créer le répertoire /home/webuser/logs.

Monit

Monit lui, va servir à redémarrer le serveur nginx s’il est en panne, redémarrer l’api si elle est innaccessible et envoyer un email d’erreur dès qu’il y en a. Pour cela, vous devrez créer deux fichiers :

  • /etc/monit/monitrc.d/votreprojet
  • /etc/monit/monitrc.d/email

Quand les fichiers sont crées et complétés, vous devrez faire un lien symbolique vers /etc/monit/conf.d de la manière suivante :

sudo ln -s /etc/monit/monitrc.d/email /etc/monit/conf.d/
sudo ln -s /etc/monit/monitrc.d/votreprojet /etc/monit/conf.d/
sudo ln -s /etc/monit/monitrc.d/nginx /etc/monit/conf.d/

votreprojet

check host nodeapp with address 127.0.0.1
    start "/sbin/start votreprojet"
    stop "/sbin/stop votreprojet"
    if failed port 3000 protocol HTTP
        request /
        with timeout 10 seconds
        then restart
        if 5 restarts within 5 cycles then timeout

email

set mailserver smtp.gmail.com port 587
    username "user@gmail.com" password "password"
    using tlsv1
    with timeout 30 seconds


set alert votremail@domain.com

set mail-format { 
    from:server@domain.net 
    subject: [production]monit alert -- $EVENT $SERVICE 
    message: $EVENT Service $SERVICE 
             Date: $DATE 
             Action: $ACTION 
             Host: $HOST 
             Description: $DESCRIPTION 
}

Start, Stop, Restart

Maintenant, si vous voulez lancer, arrêter et redémarrer l’api, vous n’aurez qu’à faire

sudo start votreprojet
sudo restart votreprojet
sudo stop votreprojet
Attention : Avec monit, si vous arrêtez l’API, elle se redémarrera automatiquement au bout de 30s.

Si vous voulez couper et relancer monit, faites juste :

sudo service monit stop
sudo service monit start

Script de mise en production

Lors de la mise à jour de l’API, tout comme pour l’installation, vous avez juste à lancer le script suivant :

#!/bin/sh
cd /home/webuser/public_html/votreprojet
sudo -u webuser -H git pull
sudo -u webuser -H npm install
sudo restart votreprojet

Le mot de la fin

Voilà. Maintenant vous êtes aptes à mettre en production votre projet NodeJS. Certains d’entre vous passeront par les tags plutôt que par la branche master pour les mises à jour de la production. Je suis bien preneur pour un script permutant ceci. De plus je n’ai pas parlé des scripts de migration pour mettre à jour la BDD, … Je me suis concentré sur l’essentiel. N’hésitez pas à me faire vos remarques.

Mon retour sur le passage de PHP à Node.js

Mon retour sur le passage de PHP à Node.js

Cela fait maintenant depuis le mois de mai (si je me rappelle bien) que je travaille sur un projet Node.JS en lieu et place du PHP. Et cela fait un bout de temps que je me dis que je dois faire un article sur les différences entre ces deux technologies WEB. Ainsi que mon retour sur cette dernière.

Avant d’aller plus en avant, je tiens à préciser à quoi nous sert Node.JS au travail : Créer une API complète (comme l’api twitter). Nous ne nous servons donc pas du tout de Node.JS pour la partie templating.

PHP, Node.JS, qu’est-ce que c’est ?

PHP

PHP est arrivé comme une technologie novatrice au début des années 2000 comme étant le langage dans le vent grâce aux choses suivantes :

  • C’est un langage interprété à la différence du C++ ou du JAVA qui nécessitent de compiler les sources pour fonctionner.
  • Il a la particularité d’être utilisé directement au sein des pages HTML grâce aux balises <?php ?>.
  • Il utilise la programmation procédurale qui est plus facile à apprendre que la programmation orientée objet.
  • Il n’est pas typé et il n’y a pas besoin de déclarer les variables avant de s’en servir.

Depuis, le langage PHP a fait son petit bout de chemin:

  • On peut installer des packages au sein de ses projets avec Composer (compatible PHP 5.3.2+).
  • On peut développer en Objet et utiliser des Designs Patterns comme le Pattern MVC grâce à différents Frameworks (Zend, CakePHP, Laravel, …).

Malgré toutes ces améliorations et l’engouement assez fort, PHP est sujet à de nombreuses vulnérabilités (Injections SQL, …) et il n’a pas de réel gestionnaire de paquets (Composer est un projet indépendant et a été inspiré par le gestionnaire NPM de Node.JS). Il n’y a pas une réelle API au sein de PHP et les performances ne sont pas toujours au rendez-vous.

De plus, de meilleures alternatives ont fait leur apparition pour le web :

  • Ruby on Rails
  • Django
  • Node.JS

Node.JS

Cette technologie est assez jeune (environ 2 ans si je ne me trompe pas), et apporte des choses innovantes (comme pour PHP à l’époque)’

  • Il permet d’exécuter du JavaScript côté serveur en utilisant le moteur de Google : Google Chrome V8 engine.
  • Il intègre nativement un gestionnaire de packages : NPM. Ce gestionnaire permet d’installer des modules soit en global, soit dans un projet.
  • Les modules Node.JS globaux apportent le plus souvent des commandes système supplémentaires. Par exemple : lancer la conversion du Less vers le CSS ou la création d’un projet express directement hiérarchisé.
  • Vous pouvez créer vos modules en code natif (C/C++) et en JavaScript.
  • Il peut faire office de serveur web sans passer par Apache ou Nginx. Mais ces derniers peuvent être nécessaires si vous voulez accéder à différents projets Node.JS sur le même port (80 et 443 par exemple) ou pour utiliser les noms de domaine.
  • Il ne bloque pas les entrées/sorties grâce à l’asynchrone du JavaScript (je n’arrive pas à mieux tourner cette phrase). Ce qui permet un gain notable des performances.

J’ai oublié certainement d’autres points importants, mais ici, je ne cherche pas à montrer tout ce qu’apporte Node.JS, mais quelles sont les choses les plus notables qu’il apporte.

C’est une technologie assez récente et bas niveau. Est-ce que dans 10 ans une autre technologie va aussi le supplanter? Possible, mais nous n’y sommes pas encore.

Comparatifs

Certains d’entre vous sont friands de comparatifs en tout genre, voici les principaux listés ici:

Mon retour

Contexte

Il faut savoir que, comme dit en introduction, j’utilise Node.js uniquement comme API RESTFul. Pourquoi ce choix? Car une API permet d’avoir différents points d’entrée et permet un plus grand large choix de technologies pour ce qui va « consommer » l’API.

Dans mon cas, je n’utilise pas du tout le moteur de templating fourni par NodeJS. Je laisse cette partie au projet de frontend. Node.js permet, grâce à express, d’effectuer des retours JSON avec une facilité enfantine.

Ensuite, notre API est RESTFul. Malheureusement, express ne suffit pas pour répondre à ce besoin. De plus, nous préférons utiliser un pattern structuré tels que le pattern MVC pour nos projets. Locomotive.js est parfait pour répondre à ce besoin.

Et pour finir, le passage à Node.JS seul ne suffit pas, un petit passage de MySQL vers MongoDB s’est avéré utile. Ça répondait à nos besoins puis les résultats de MongoDB sont directement utilisables par Node.JS vu que ce sont des objets/tableaux JSON.

Retour d’expériences

Le plus dur je trouve avec le passage de PHP à Node.js est ce principe d’asynchrone. Dès que vous appelez une fonction avec un callback, il faut bien penser à chaque cas de retour sans en omettre un seul sous peine de se retrouver avec la requête bloquée en attente d’une réponse.

De base, Node.js met en cache tout votre projet avant de l’exécuter. Vous devrez donc penser à bien le relancer après chaque modification de votre code. J’ai eu l’air fin à chercher pendant 15 minutes pourquoi mes modifications n’étaient pas prises en compte.

Sinon, en soi, Node.js est vraiment un plaisir à utiliser. Bien entendu, c’est du JavaScript et sans rigueur, on peut très très vite se retrouver avec du code sale.

Dernier point. Pour les développeurs sous Windows : changez d’OS. La plupart des modules utilisant des librairies natives ne fonctionnent pas chez vous et la ligne de commande étant quand même assez utilisée et aux vues de votre console assez préhistorique, je vous conseille de développer sous Linux ou Mac.

Cross Domain, Iframe, LocalStorage et Html5

Cross Domain, Iframe, LocalStorage et Html5

Aujourd’hui je vais vous parler d’une chose sur lequel j’ai butté une journée entière. Voici ce que je devais réaliser :

Envoyer des infos en arrière plan dans le localStorage du domaine B depuis le domaine A

Si vous ne le savez pas, les navigateurs ont un localstorage de 5Mo (10Mo pour certains navigateurs) par Domaine. De plus, vu que le localstorage est côté navigateur, nous devrons le manipuler avec du JavaScript. C’est pourquoi, la réponse logique (et après recherche) reste donc l’utilisation des IFrames. Le souci, c’est que maintenant, les navigateurs modernes ne permettent plus la manipulation des IFrames si son domaine est différent de la page source.

En cherchant un peu plus, je suis tombé sur la fonction PostMessage() introduite avec HTML5 permettant d’outrepasser cette limitation tout en gardant le côté sécurisé.

Justement, ce problème va nous permettre de voir plusieurs technologies propres à l’HTML5 :

  • LocalStorage : Permet de stocker des valeurs au sein du navigateur sans limite de durée. Le LocalStorage est rattaché au domaine.
  • PostMessage : Fonction propre aux IFrames permettant d’envoyer des événements depuis la page parente. Fonctionne si l’Iframe est dans un domaine différent.

Nous allons voir chacune des deux parties avec le code à implémenter.

Tout à l’heure, j’ai parlé à plusieurs reprises de domaine. En fait il s’agit du site web. Si vous essayez de communiquer avec une iframe ciblant un site web différent du votre (par exemple google.fr alors que vous êtes foo.bar), alors les navigateurs bloqueront la communication par mesure de sécurité.

Domaine A

Dans le domaine A, nous allons voir 2 parties. La vue HTML avec la mise en place de l’IFRame (c’est tout bête mais il y a un petit détail important), puis la partie Javascript avec l’utilisation de PostMessage.

Vue HTML

<html>
    <head>
        ...
    </head>
    <body>
        ...
        <iframe src="http://mondomaineb/foo.html" frameborder="0" style="display: none;" id="postmessage"></iframe>
    <body>
</html>

Partie Javascript

//...
//le [0] sert à récupérer l'objet DOM
var iframe = $("#postmessage")[0].contentWindow;
iframe.postMessage({
    foo : 'value1',
    bar : 'value2'
}, "*");
//...

Domaine B

Dans le Domaine B, seule la partie Javascript va être necessaire. Néanmoins, si vous devez communiquer un retour avec le domaine A, vous devriez encore repasser par une IFrame. Mais ceci ne concerne pas cet exemple.

Il faut savoir que, pour pouvoir capturer un événement postMessage, nous devons ajouter un Listener sur l’événement message. Si vous oubliez cette partie, votre postMessage communiquera avec un mur. De plus, la fonction lancée par ce Listener n’a qu’un seul paramètre : Le paramètre event. Grâce à lui, vous pouvez connaître l’origine du message et ainsi le traiter uniquement s’il vient du Domaine A.

//...
function postMessageB(evt){
    if(
        evt.origin === 'http://mondomaineA'
    ){
        var foo = evt.data.foo;
        var bar = evt.ata.bar;

        // affichera dans votre navigateur le message "value1 value2" depuis l'iframe.
        alert(foor+" "+bar);   
    }else{
        return;
    }
}

window.addEventListener("message", postMessageB, false);
//...

Conclusion

Voilà. Normalement, vous savez dorénavant utiliser postMessage. Si vous avez des questions, des soucis ou que vous souhaitez aussi me corriger, n’hésitez pas à me laisser un commentaire. Sur ce, bon week-end à tous.

Débuter sur Backbone.JS

Débuter sur Backbone.JS

Aujourd’hui aucun tutoriels mais la présentation d’une technologie Web que je commence à apprendre à utiliser et qui s’avère rudement bien pensée.

Comme le nom de l’article le suggère, Backbone est une library Javascript. Mais cette library a la particularité d’utiliser le patern MV* (je ne dis pas le C car il n’y a pas réellement de controllers). De là vous pouvez rattacher des événements à vos models pour effectuer des actions javascript. Si en plus vous rajoutez une couche médiateur/façade, vous aurez une base en béton.

Malheureusement je n’ai pas assez d’expérience dessus pour vous faire une introduction ou vous en dire plus donc voici les différents liens utiles pour découvrir cette library et peut-être voudriez vous l’adopter :

Et voici une liste non exhaustive des sites utilisant cette technologie :
  • DocumentCloud
  • Flow
  • Foursquare
  • Groupon
  • Basecamp
  • Stripe
  • Trello
  • Diaspora (oui il est bien vivant ce facebook killer)
Voilà, si vous avez d’autres liens utiles sous le coude n’hésitez surtout pas à les partager. Je suis très intéressé par tout ce qui touche à cette library.