Tutoriel : créer un chat avec Meteor.js 1.0

Décembre 2014

Voici un article un peu plus court que d'habitude pour vous expliquer comment créer un chat très simple avec Meteor.js.

Meteor.js

Tout d'abord, il faut préciser ce qu'est Meteor.js. Il s'agit d'un outil qui permet de développer très rapidement des applications web, multi-utilisateurs et réactives.

Meteor.js s'appuie sur des technologies bien connues des startup à la pointe :

  • Node.js
  • Javascript
  • MongoDB

On est donc face à une stack très nouvelle : du Javascript côté client comme serveur et une BD NoSQL. Si vous ne connaissez pas tous ces outils, il faudra un peu vous documenter. Mais cela reste très facile d'accès pour quelqu'un qui a déjà programmé en Javascript et qui connait un peu les architectures serveur.

La particularité de Meteor.js vient du fait qu'une modification effectuée sur la base de données et automatiquement répercutée (si nécessaire et si c'est l'effet souhaité) pour tous les utilisateurs connectés au site Internet. Il s'avère donc très facile de créer des applications de discussion ou de chat.

Pourquoi utiliser Meteor.js ?

Pourquoi pas ?

Plus sérieusement, Meteor.js permet de développer des applications Web très rapidement. Cet outil s'occupe de la gestion des utilisateurs, de la base de données et un seul langage de programmation est utilisé (Javascript).

Il est maintenant en version 1.0 et de plus en plus de startup l'utilise pour lancer une première version de leur produits.

Une particularité intéressante de Meteor tient au fait que les modifications apportées à l'application sont automatiquement envoyées aux utilisateurs. En effet, Meteor utilise le cache du navigateur pour conserver des données. Si celles-ci changent ou que la logique de l'application est modifiée, tous les clients (navigateurs) sont mis à jour.

Un système de déploiement de l'application fait qu'il est aussi très simple d'installer Meteor sur un serveur. Et, pour compléter cela : les applications fonctionnent très bien sur les smartphones récents !

Il est possible que Meteor.js devienne un des framework web les plus populaires dans les 5 ou 10 ans à venir.

Installation de Meteor.js

Précision : ce tuto a été réalisé sur Meteor en vers 0.8.3. Une version plus récente 1.0 vient de sortir et l'API est maintenant stable. Il y a donc des choses qui sont peut être plus facile à réaliser maintenant. De toute façon, d'autres articles suivront sur Meteor.js dans les mois à venir.

Tout d'abord rendez-vous sur le site de Meteor à la rubrique "Install". Vous devrez avoir une machine type UNIX pour installer Meteor. Donc, si vous êtes sous Linux ou Mac OS X c'est parfait. Pour les utilisateurs Windows, une version spéciale serait en cours de développement, et si c'est votre cas je vous conseille d'utiliser une machine virtuelle.

La commande à exécuter est simple :

    curl https://install.meteor.com/ | sh

Et voilà, Meteor est installé.

Vous pouvez créer une application vierge avec cette commande :

    meteor create nom_projet

Soit, dans notre cas :

    meteor create minichat

Vous êtes maintenant pret pour vous lancer dans le développement de votre première application Meteor.js. Pour lancer l'application il suffit de faire :

    cd minichat
    meteor

Vous avez accès à votre application depuis cette adresse de votre navigateur http://localhost:3000/.

Architecture de l'application

Par défaut, Meteor a créé ces fichiers :

    minichat.css	minichat.html	minichat.js 

Comme leur nom l'indique, chaque fichier a une fonction bien précise :

  • minichat.css : feuille de style de votre application
  • minichat.html : template HTML de votre application
  • minichat.js : code Javascript de votre application

Il n'y a qu'un seul fichier Javascript car Meteor mélange la logique côté serveur et côté client. Cela peut surprendre mais c'est comme cela que ce framework a été pensé : vous pouvez vous organiser comme vous souhaitez.

Personnellement, je préfère les choses un peu plus carrées. Je vous propose donc cette organisation en sous-dossier :

    client/client.js
    client/minichat.css
    client/minichat.html
    server/server.js 

Je trouve qu'il est bien plus simple de s'y retrouver dans la logique de l'application si on sépare la partie client de la partie serveur. Les fichiers clients.js et server.js devront donc être créés par vos soins.

La partie HTML et css

C'est la partie la plus simple si vous êtes un habitué du web. C'est dans les fichiers HTML et CSS que vous définirez l'interface utilisateur pour votre application web (chat).

Pour les besoins de ce tutoriel, la partie visuelle sera rudimentaire. Mais sachez qu'il est possible de faire des choses très sympathiques avec Bootstrap ou un autre framework.

Voici le contenu du fichier CSS :

    /* CSS declarations go here */

C'est le contenu par défaut et nous n'allons pas le modifier. Libre à vous de le faire si vous voulez ajouter une touche de design visuel à votre application de chat.

Voici le contenu du fichier HTML :


<head>
      <title>minichat</title>
    </head>

    <body>
      <h1>Mini Chat</h1>
      
      {{> hello}}
    </body>

    <template name="hello">
      <form id="formulaire">
            <label>Pseudo</label><input type="text" id="pseudo" name="pseudo"><br>
            <label>Message</label><textarea name="message" id="message"></textarea>
            <input type="submit" value="Envoyer message">
       </form>
       
        <div>
        {{#each derniersMessages}} 
            <p>
                <label>{{pseudo}}</label>
                <em>{{time}}</em><br>
                {{message}}
            </p>
        {{/each}} 

        </div>

    </template>

Cette fois quelques explications s'imposent.

Il y a déjà un lien vers un template :

    {{> hello}}

Il s'agit d'une référence vers la balise template qui porte le nom "hello". Ensuite, un formulaire simple est présent dans ce template.

On trouve aussi dans ce template une boucle sur les derniers messages du chat :


    {{#each derniersMessages}} 
        <p>
            <label>{{pseudo}}</label>
            <em>{{time}}</em> <a href="" class="voirMessage">#{{chatroom}}</a><br>
            {{message}}
        </p>
    {{/each}} 

Il me semble que pour tout programmeur, cette partie se passe d'explication. Les templates Meteor utilisent le format SpaceBars (dérivé de HandleBars), il sera nécessaire de vous reporter à la documentation pour apprendre toutes les finesses de ce système.

C'en est terminé pour la partie visuelle de l'interface ! Nous pouvons maintenant entrer dans le coeur du système de chat en débutant par la partie serveur.

Le serveur

Ici, nous allons travailler sur le fichier server/server.js donc voici le contenu :

    if (Meteor.isServer) {
        
        Messages = new Meteor.Collection('messages');
        
        Meteor.methods ({
            ajouteMessage : function (post) {
                var timestamp = Math.round(new Date().getTime() / 1000);
                Messages.insert({
                    pseudo : post.pseudo,
                    message : post.message,
                    time : timestamp
                });
            }
        });

        Meteor.publish('messages', function(salon) {
           return Messages.find( {}, {sort : {time : -1}, limit : 500} );
        });

        Meteor.startup(function () {
          // code to run on server at startup
        });
    }

Tout d'abord, le fichier contient un test :

    
    if (Meteor.isServer)

Il n'est pas du tout obligatoire, mais il vous sera utile si vous décidez de réunir la partie client et la partie serveur dans le même fichier.

Ensuite, on décide de déclarer une collection :

    Messages = new Meteor.Collection('messages');

Cette collection va permettre d'ajouter des messages dans la base de données. Il s'agit d'une collection MongoDB.

On prend donc le temps de déclarer les méthodes qui vont interragir avec cette collection. Dans ce cas, c'est simple puisqu'on a besoin côté serveur d'une seule méthode. Elle va permettre l'ajout de messages dans la collection :

    Meteor.methods ({
        ajouteMessage : function (post) {
            var timestamp = Math.round(new Date().getTime() / 1000);
            Messages.insert({
                pseudo : post.pseudo,
                message : post.message,
                time : timestamp
            });
        }
     });

Simplement, on prend les variables contenus dans le "post" du formulaire et on les ajoute à la collection des Messages.

Enfin, on publie la collection Messages pour que le client (et les visiteurs de votre application) voient les derniers messages :

    Meteor.publish('messages', function(salon) {
       return Messages.find( {}, {sort : {time : -1}, limit : 500} );
    });

L'idée est ici de trouver les 500 messages le plus récents.

La dernière fonction Meteor.startup est conservé au cas où, mais elle ne sert à rien dans ce tutoriel.

Le client

Passons maintenant au client qui est légèrement plus compliqué que le serveur (et encore...).

C'est le fichier client/client.js qu'on va éditer :

    if (Meteor.isClient) {
        Messages = new Meteor.Collection('messages');
        
        Deps.autorun(function() {
          Meteor.subscribe('messages', { 
                onReady : function() {
                    Session.set("active", true); // pour dire que c'est synchronisé (donc on peut commencer à rafraichir le template)
                }
          });
        });

      Template.hello.events({
         'submit form': function(event) {
            event.preventDefault();
            var post = {
                pseudo : $(event.target).find('[name=pseudo]').val(),
                message : $(event.target).find('[name=message]').val()
            }
            if ( (post.message != "") && (post.pseudo != "") ) {
                Meteor.call("ajouteMessage", post);
            }
        }
      });

       Template.hello.helpers({       
           derniersMessages : function() {
                 if (Session.get("active")) {
                     return Messages.find({}, {sort : {time : -1}, limit : 500});
                 } else {
                     return [];
                 }
            }
       });
    }

Une fois de plus on conserve le test sur le client. Mais ce n'est pas obligatoire. On déclare aussi la collection de la même manière que sur le serveur :

    Messages = new Meteor.Collection('messages');

Pour que le client reçoivent correctement les messages, il faut s'assurer que le serveur les envoient bien. Pour cela, on va s'assurer que le client affiche quelque chose que lorsqu'il aura reçu les messages. Ce n'est pas obligatoire mais je trouve cela plus compréhensible pour l'utilisateur :


    Deps.autorun(function() {
          Meteor.subscribe('messages', { 
                onReady : function() {
                    Session.set("active", true); 
                }
          });
        });

On a choisi d'utiliser une variable de session et de la mettre à true lorsque tout est parfaitement synchronisé.

On passe ensuite aux fonctions du template hello définis dans le fichier HTML. Nous avons deux choses à réaliser pour que cela fonctionne :

  • envoyer les données du formulaire pour poster un Message
  • récupérer les derniers messages

Pour réaliser le "post" du formulaire, on utilise une fonction lié à un évènement. Cet évènement est l'envoi du formulaire (submit) :


    Template.hello.events({
         'submit form': function(event) {
            event.preventDefault();
            var post = {
                pseudo : $(event.target).find('[name=pseudo]').val(),
                message : $(event.target).find('[name=message]').val()
            }
            if ( (post.message != "") && (post.pseudo != "") ) {
                Meteor.call("ajouteMessage", post);
            }
        }
      });

Il ne s'agit pas d'une solution idéale car elle ne fonctionne pas si on a plusieurs formulaires. Mais je trouve que cela représente bien la façon dont fonction Meteor.

Ensuite, il faut récupérer les derniers messages. C'est ici que la variable de session se révèle utile :


    Template.hello.helpers({       
           derniersMessages : function() {
                 if (Session.get("active")) {
                     return Messages.find({}, {sort : {time : -1}, limit : 500});
                 } else {
                     return [];
                 }
            }
       });

Je pense que cette dernière méthode est assez explicite.

Et voilà, c'est terminé !

Test du chat Meteor.js

Vous pouvez maintenant lancer l'application en vous plaçant à la racine de votre répertoire projet *minichat* et lancer l'application à l'aide de la commande :


    meteor 

Ouvrez un navigateur à cette adresse :


    http://localhost:3000/

Afin de voir les capacités réactives, ouvrez maintenant deux navigateurs et placez les fenêtres côte à côte :

résultat du tuto meteorjs

Vous verrez que les messages publiés dans une fenêtre apparaîssent pratiquement instantannément dans l'autre fenêtre.

Maintenant, stoppez l'exécution de l'application avec les touches CTRL + C.

Relancez l'application avec la commande meteor et, magie, les messages sont toujours là grâce à la sauvegarde dans MongoDB.

Vous venez de réaliser un chat avec Meteor.js.

Aller plus loin avec Meteor

Vous pouvez télécharger les sources de ce tutoriel : Minichat en Meteor.js.

Maintenant, je vous préviens : ce tutoriel ne traite qu'une infime partie de Meteor.js.

Pire : ce que je vous ai présenté n'est pas la meilleure façon d'utiliser ce framework. Cependant, je pense que cela a le mérite d'aborder de façon pratique ce fantastique outil.

Enfin, un élément important : avec l'application présentée dans ce tutoriel, les utilisateurs peuvent modifier l'intégralité de la base de données. En effet, par défaut Meteor synchronise les base de données entre les clients et le serveur.

Pour supprimer cela, il est nécessaire de lancer cette commande dans votre projet :


    meteor remove autopublish

Je vous invite à vous référer à la documentation sur le site http://meteor.com/ pour en savoir plus.

Et voilà, c'est tout pour le moment, n'hésitez pas à me contacter si vous avez des besoins particuliers.

Pour d'autres articles, cliquez ICI.