Archives du blog

Angular, Express et Socket.io

Vous savez, si vous lisez le blog de Ninja Squad régulièrement, que nous donnons des cours dans différents établissements, de la fac aux écoles d’ingé, en passant par l’IUT. Avec cette nouvelle année scolaire, nous voici repartis!

Je donne depuis quelques années un cours sur les web services à l’INSA, à l’invitation du Docteur Ponge : c’est l’occasion de parler SOAP (beurk), REST (yay!) et Websocket (re-yay!).

Cette année, je veux faire une démo des websockets pour que cela soit un peu moins mystérieux. Faire un peu de code live est toujours un exercice périlleux, mais c’est un bon moyen pour échanger avec les étudiants et leur présenter un certain nombre de technologies, qu’ils connaissent parfois de nom ou pas du tout.

Les websockets sont l’occasion idéale de faire une application web basique, mais permettant d’introduire quelques concepts du Web parfois mal connus (HTML, CSS, Javascript) et un peu de code plus innovant (Node.js, Express, Socket.io, AngularJS, Bootstrap), de discuter sur l’histoire du Web, le fonctionnement des navigateurs (Chrome, Firefox, V8…) et quelques outils pratiques (npm, Git). Bref, d’apporter un peu de culture générale de notre métier, chose que j’appréciais beaucoup lors des interventions de professionnels lorsque j’étais étudiant.

Après cette remise en contexte, passons aux choses sérieuses!

Il me fallait donc un exemple d’application, qui me prenne une trentaine de minutes à réaliser au maximum. J’ai choisi de faire simple : une application de vote qui permet de choisir votre framework Javascript préféré, et de voir les résultats en temps réel. Nous allons voir les différentes étapes pour y parvenir.

Vous trouverez le nécessaire pour utiliser l’application sur le repo Github de Ninja Squad.

Express/Angular

La première branche Git, nommée `express` met en place une application Node.js/Express minimale.

    var express = require('express')
      , app = express()
      , server = require('http').createServer(app);
    
    app.use(express.static(__dirname + '/'));
    
    server.listen(9003);

L’application Node.js va servir les ressources statiques sur le port 9003. On peut alors ajouter le fichier HTML de notre application, qui contient basiquement :

    <div class="row">
      <div class="col-xs-4 vote"> {{ vote.choice }} </div>
      <div class="col-xs-4 vote"> {{ vote.votes }} </div> 
      <div class="btn btn-primary col-xs-4">+1</div>
    </div>

Pour chaque vote de la collection `votes`, le choix (VanillaJS, AngularJS, BackboneJS ou EmberJS), le nombre de vote pour ce choix et un bouton pour ajouter un vote seront affichés. Cela est réalisé en utilisant la directive `ng-repeat` d’Angular.

Le bouton de vote comporte l’attribut `ng-click` qui permet de lui lier une fonction à exécuter. Cette fonction `voteFor` est définie dans le controller :

	function VoteCtrl($scope){
      $scope.votes = [ { choice: 1, label: 'VanillaJS', votes: 0 }, { choice: 2, label: 'AngularJS', votes: 0 }, { choice: 3, label: 'BackboneJS', votes: 0 }, { choice: 4, label: 'EmberJS', votes: 0 }];

      $scope.voteFor = function(choice){ $scope.votes[choice-1].votes++; }
    }

Le controller Angular initialise les votes et définit la fonction de vote, qui ajoute simplement 1 aux votes du choix cliqué.

Etape 1 terminée! Passons maintenant à l’intégration de Socket.io.

Socket.io

Socket.io est l’une des librairies les plus utilisées pour les websockets dans Node (même si elle est maintenant concurrencée par d’autres comme SockJS). Elle a l’avantage de gérer le fallback si les websockets ne sont pas disponibles, et d’être très simple à utiliser à la fois côté client et côté serveur.

La branche `websocket` contient le code correspondant. Outre l’installation de socket.io (`npm install` is your best friend), il nous faut modifier un peu le serveur :

    io.sockets.on('connection', function (socket) {
      socket.emit('votes', { votes: votes });
      socket.on('vote', function(msg){
      	votes[msg.vote-1].votes++;
      	io.sockets.emit('votes', { votes: votes });
      })
    });

L’implémentation est naïve mais suffit à la démonstration : à la connexion d’un nouveau client (`socket.on(‘connection’, …)`), on envoie les votes dans l’état du moment (`socket.emit`). Puis, lorsque l’on recevra un vote (`socket.on(‘vote’, …)`), on incrémente les votes du choix correspondant et on informe tous les participants avec les nouvelles valeurs (`io.sockets.emit`).

Reste à mettre à jour le client pour communiquer avec les sockets :

    var socket = io.connect('http://localhost:9003');

    $scope.voteFor = function(choice){
      socket.emit('vote', {vote : choice })
    }

    socket.on('votes', function(msg){
      $scope.votes = msg.votes;
      $scope.$apply();
    });

On commence par se connecter aux websockets (`io.connect`). La fonction `voteFor` est modifiée pour maintenant envoyer un évenement de vote au serveur (`socket.emit`). Enfin, à chaque fois que les votes sont reçus, les votes du `$scope` Angular sont mis à jour. Petite subtilité : comme cette mise à jour intervient en dehors de la boucle d’exécution d’Angular, il nous faut appeler la fonction `$apply()` pour que le framework prenne les nouvelles valeurs en compte et rafraîchisse les vues.

Nous sommes prêts : si vous ouvrez cette application dans deux onglets, vous pourrez la voir se mettre à jour en temps réel!

A noter que le brillant Brian Ford de l’équipe Angular propose un service Angular pour Socket.io, afin de simplifier son utilisation et notamment les appels à `$apply()`.

Vous pouvez voir une démo en ligne, déployé sur Heroku (le code nécessaire pour cette partie est également sur le repo Github).

Espérons que ce petit essai vous plaise et plaise à nos étudiants!

Trello, encore un peu de Node.js

Cette semaine (le 13 Septembre exactement), FogCreek a annoncé un nouvel outil. Peut être ne connaissez vous pas FogCreek : c’est la société de Joël Spolsky, aussi fondateur de StackOverflow et auteur de l’excellent blog, Joël on Software.

L’outil s’appelle Trello et sert à gérer les différentes tâches de vos projets, à la manière d’un whiteboard avec post-it que l’on deplace. Vous pouvez créer une nouvelle tache, représentée par une carte, l’assigner a un utilisateur, commenter cette tache, y ajouter une liste de choses a faire (avec une barre de progression qui se remplit au fur et a mesure que chaque item de la liste est effectué). On peut également déplacer ces taches entre les différentes colonnes, y ajouter des pieces jointes, des labels, tout ca avec des raccourcis claviers! Lisez le billet de Spolsky a l’occasion du lancement pour avoir plus de détails sur les usages qu’il est possible d’en faire : FogCreek utilise par exemple un ecran 42 pouces pour afficher Trello dans leurs locaux! Un autre article en français si vous êtes allergique à la langue de Shakespeare.

Mais surtout Trello est gratuit, donc foncez vous inscrire et essayer ! On l’utilise depuis quelques jours sur un petit projet, c’est très pratique et fun.

Si vous avez lu le titre de l’article, vous savez que je ne voulais pas seulement vous parler de l’outil Trello, mais aussi des technologies qu’il utilise. Essayez d’accéder à Trello depuis votre téléphone ou de réduire votre écran : la CSS est très bien faite et s’adapte parfaitement quelque soit la résolution d’écran. Un coup de Firebug plus tard, je me suis rendu compte que de plus ca sentait l’application Node.js à plein nez. Effectivement après quelques recherches plus poussées, j’en suis arrivé à une conclusion qui s’est trouvée confirmer par un employé de FogCreek sur son Twitter.

La stack compléte semble être :

Node.js.

– Module Express.

– Module Async qui permet de faire de l’asynchrone en Javascript (ajoute des focntions map, reduce, filter et du contrôle de workflow).

– Backbone.js et Underscore.js (je vous laisse lire les très bon articles de Philippe Charrière) pour le MVC côté client.

– La partie CSS utilise le module Less (c’est l’objet de mon prochain article).

– Utilisation massive des websockets grâce à Socket.io (vous pouvez le voir en ouvrant de multiples onglets et observer les modifications qui se répercutent – article à suivre également).

CoffeeScript pour simplifier l’écriture du Javascript et JQuery.

– MongoDb avec Mongoose pour les données persistantes.

Redis pour les données non persistantes du type session.

– Pour le debug, Node Inspector est évoqué.

A priori le mot d’ordre chez FogCreek c’est de ne pas utiliser une techno qui a plus de 2 ans : so hype ! Spolsky devrait écrire quelques articles dans les prochains jours sur le pourquoi de ces choix, je vous conseille de suivre le blog de Trello si cela vous intéresse. Dans tous les cas, voilà peut être la killer-app de Node.js.

Edit 19/01/2012 : l’article est enfin sorti et confirme la stack décrite ici, enjoy!

Node, Express et Jade

Après un article de présentation et un premier “Hello world”, passons à la suite. Nous avons créé un serveur http basique. Pour créer une véritable application web, il reste encore du travail, à minima créer des pages qui seront renvoyées par le serveur. D’où notre travail du jour :
– créer les vues de l’application,
– créer le routage des requêtes afin de renvoyer la bonne vue.
L’idée est de créer un affichage du cours des actions d’une bourse virtuelle. Pour cela, on ne va pas tout faire nous même. En avant !

Quand je vous disais que Node.js fourmillait de modules, je ne mentais pas. Différentes solutions de moteur de template  s’offrent à vous, ou mieux des frameworks web (qui s’appuient donc sur des moteurs de templating, mais aussi des modules CSS, de routage etc…).

Express  est probablement le framework le plus connu et utilisé. Développé par le talentueux TJ Holowaychuk, Express s’appuie sur Connect  (un framework de serveur http qui regroupe un ensemble de middleware, inspiré de Rack). Le toujours très bon site howtonode en donne une explication intéressante.

Il utilise par défaut le moteur de template Jade  mais d’autres sont également disponibles.
Bien d’autres solutions de frameworks web existent et vous allez trouver des fans de chacune. Si vous avez un module préféré, n’hésitez pas à le signaler en commentaire.

Suivons donc la hype, et découvrons Express et Jade!

Installation express

Comme souvent on trouve moult ressources  pour bien installer Express. Si vous ne l’avez pas déjà fait, je vous conseille d’installer npm (Node Packet Manager), utilitaire très pratique qui se charge de récupérer pour vous les modules que vous voulez et de les installer (vous avez dit Maven ?). L’installation d’Express par NPM se fait alors en une ligne de commande. Une fois Express installé, créez un nouveau projet ‘shares’ avec la commande

express shares

Si vous explorez le dossier créé (ou directement sur Github ), vous trouvez une architecture typique projet web a la Rails/Grails/Play! :
– un fichier package.json équivalent à un pom.xml
– un dossier views pour les vues de l’application
– un dossier public qui contient les différentes ressources (images, styles, js)
– un fichier principal app.js

Ce dernier nous intéresse plus particulièrement, on y trouve deux parties intéressantes :
– la partie Configuration avec déjà quelques modules déclarés
– la partie Routes, qui permettra de définir quelle vue sera renvoyée pour une route donnée.
Le serveur est lancé sur le port 3000, donc si vous avez bien suivi un

node app.js

suivi d’un saut dans le navigateur vous amène à une belle page d’accueil.

Non ? Alors il vous manque peut être quelques modules : comme on le ferait pour un build Maven il faut récupérer les dépendances du projet avant de pouvoir travailler.

npm install -d

s’en charge pour vous. On relance le serveur et voilà !

Ma première route

Nous allons modifier la route existante pour la remplacer par une a nous

app.get('/', function(req, res){
 res.render('shares', {title : 'Shares', shares : shares});
});

Ainsi une requête sur l’url de notre serveur renverra la vue shares à laquelle nous passons un ensemble de variables (qui seront utilisées pour générer la vue d’après le template comme nous allons le voir incessamment).
Ces variables sont donc le titre de la page et un objet qui représente un tableau d’actions, que nous devons donc définir.

var shares = [{name:"Google",price:120}, {name:"Apple",price:132}, {name:"Microsoft",price:92}]

Chaque action est un objet simple composé d’un nom et d’un prix.

Les routes peuvent également récupérer des paramètres de l’url : si on ajoute une route comme la suivante

app.get('/:name', function(req, res){
 res.render('shares', {title : req.params.name,
    shares : shares.filter(function(share){return share.name.toLowerCase() == req.params.name.toLowerCase()})});
});

alors accéder à la page ‘/google’ donnera une page dont le titre est ‘google’ et la seule action listée celle de … Google.
Vous pouvez voir le code modifié ici.

Passons maintenant à l’écriture de ce template !

Un moteur de template qui envoie

Quel que ce soit votre langage/framework préféré, si vous faites du web, il faut bien écrire les pages html. Et il faut reconnaître que c’est rarement la partie la plus excitante, il faut penser à bien fermer ses balises, à choisir des ids et des classes pertinents, tout en se préparant à la grande bataille du CSS qui s’annonce. Boring…

Les rubyistes ont souvent de bonnes idées et on en trouve dans Rails notamment par poignée (quand on est un profane et curieux comme moi, la série de screencast Railscast est une bonne ressource pour découvrir et se tenir informé). L’une de ses bonnes idées se nomme Haml et sa devise donne le ton : « markup haiku ». Haml vise à remplacer les gros templates hideux par quelque chose de plus léger (poétique serait quand même un peu exagéré…). Mais nous ne sommes pas là pour parler Ruby. En revanche Haml a un successeur spirituel dans le monde Javascript et il s’agit de Jade (écrit par le même développeur qu’Express, qui est décidément un garçon très occupé). Le plus simple pour comprendre est de voir ça en action.

Vous avez devant vous votre IDE/éditeur de texte préféré, page blanche et vous entrez

html

Une fois compilé par Jade, ce tag se transforme en

<html></html>

Vous voulez ajouter une div avec un id

div#price 12 euros

va donner

<div id=”prices”>12 euros<div>

ou encore plus simplement

#price 12 euros

car le tag par défaut est une div.

On peut également ajouter une classe

div.prices

ou

.prices

donnera

<div class=”.prices”></div>

Besoin d’ajouter un attribut ?

a(href=’/prices’) Prices

donne

<a href=’/prices’>Prices</a>

Oh et j’oubliais, la déclaration de doctype s’écrit avec un ‘triple bang’ (!!!)

Nice ? Un peu de dynamique maintenant. Si nous avons un article avec un prix, et que l’on passe cet objet au template suivant :

#price #{item.price} euros

nous obtenons

<div id=”price”>12 euros</div>

Ces deux screencasts vous emmèneront un peu plus loin dans la découverte si vous le désirez.
Vous avez maintenant installé Express et eu un aperçu de Jade. Il est temps de faire notre premier template Jade pour Express.

Si vous ouvrez le fichier layout.jade présent dans le répertoire view vous trouvez :

!!!
html
 head
   title= title
   link(rel='stylesheet', href='/stylesheets/style.css')
 body!= body

On retrouve la déclaration de la doctype (triple bang), les balises html, head et body bien connues. On voit également comment s’effectue le chargement d’un style, et l’utilisation de la variable title passée en paramètre du template. A l’instar de Ruby, l’indentation est significative : un bloc indenté est un sous bloc du bloc précédent.
Ce layout est utilisé a chaque appel, et body sera remplacé par le template appelé (le template shares dans notre exemple).

Le template index.jade contient la page d’accueil. Elle ne nous sera plus nécessaire nous pouvons la supprimer. En revanche il nous faut créer la vue shares. Pour cela on peut créer un fichier shares.jade ou un dossier shares contenant un fichier index.jade. Cette deuxième méthode est retenue car nous allons utiliser plusieurs fichiers pour cette vue et ils seront regroupés dans ce dossier par soucis de lisibilité.

Voici a quoi va ressembler votre fichier index.jade

h1 Share's price
.shares
 != partial('share', shares)

La balise h1 contiendra le texte “Share’s price” puis une div avec la classe shares contiendra une “vue partielle”. Cette déclaration permet de façon simple de dire au template que pour chaque action de la collection ‘shares’ passée en paramètre, il faudra effectuer un rendu particulier. Ce sous template est créé dans un template annexe nommé ‘share.jade’ :

.share
 .name #{share.name}
 .tag
   .price(id=share.name) #{share.price}$

Ce template va être appelé pour chaque action, et pour celle-ci va créer une div de classe ‘share’ contenant une div ‘name’ avec le nom de l’action et une div ‘tag’ pour le prix. Cette dernière div contient une div ‘price’ dont l’identifiant est dynamique (pour les besoins du prochain billet) et le prix en $.

Si on relance le serveur vous devez avoir à l’écran la liste des actions !

Et pour tester la deuxième route, si l’on accède à la page ‘/google’, nous obtenons :

Vous pouvez récupérer les sources de cet article sur Github

git clone git@github.com:cexbrayat/shares.git

Pour lancer l’application

npm install -d
node app.js

Jade commence à se répandre, on trouve ainsi Scalate qui s’appuie dessus et est disponible comme moteur de template pour vos projets java (on trouve aussi un module Play!). C’est un outil très intéressant et pratique, à suivre et surveiller!

 

La prochaine fois on découvrira plus en avant Express et on parlera CSS !