Accueil > Frameworks > Introduction à Ember.js

Introduction à Ember.js

Cette année 2012 à été riche pour l’écosystème javascript et particulièrement pour les frameworks MVC côté client.

Je me propose dans cet article de vous présenter un challenger méconnu à côté de Backbone.js ou de Angular.js.

 

Ember.js

Ember.js

 

Ember.js est un framework MVC en javascript dont le but est de créer des applications web se rapprochant des applications desktop, dites “single page web application”.

Pour voir quelques exemples d’applications en production réalisées avec Ember.js, rendez vous sur Groupon, Capitaine Train ou encore Travis CI.

L’idée derrière les “Single Page Web App” est grossièrement de télécharger l’intégralité de l’application à la première requête de l’utilisateur, puis de communiquer uniquement avec le serveur par requête Ajax pour manipuler les données via une API REST si possible. L’application “Ember” est également  découpée selon le fameux pattern MVC afin d’apporter une séparation des responsabilités côté client permettant une plus grande maintenabilité … enfin vous connaissez la musique.

Ember.js arrive lentement mais surement à maturité avec la version 1.0 qui se profile à l’horizon. Critiqué par le passé pour ses nombreux changements rendant certaines montées de version sportives, l’équipe de développement souhaite à présent stabiliser le code. Il est intéressant de savoir que Ember.js partage une certaine similarité de philosophie avec Ruby, ceci est dû à l’origine du projet ainsi qu’à ses membres avec notamment Yehuka Katz, développeur de Ruby on Rails et jQuery.

Les tâches effectuées par des applications web sont répétitives. Tout se résume souvent à récupérer des données depuis un serveur, les afficher à l’écran puis mettre à jour les informations lorsqu’elles changent. Voyons à présent quels sont les outils proposés par Ember.js pour nous faire gagner du temps et cesser de nous préoccuper de la génération du DOM.

A better JavaScript

Au delà du MVC que nous verrons par la suite, ember.js apporte un certain nombre d’améliorations au javascript qui apparaîtront pour certaines avec ECMA Script 6.

●     un système de classe :

1
2
3
4
Person = Ember.Object.extend({
  firstName : null,
  lastName : null
});

●     les Mixins :

Les mixins  qui permettent de composer des aspects au sein d’objet.

1
2
3
4
5
6
Speaker = Ember.Mixin.create({
  hello: function(){
    alert(this.get(‘firstName’) +” “+ this.get(‘lastName’) );
  }
});
Person = Ember.Object.extend(Speaker);

On peut à présent appeler la méthode ‘hello’ sur les instances de Person.

●     Computed properties

Tout simplement une propriété dont la valeur est issue d’une fonction.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Person = Ember.Object.extend({
  firstName: null,
  lastName: null,
  fullName: function() {
    var firstName = this.get('firstName');
    var lastName = this.get('lastName’');
  return firstName + ' ' + lastName;
  }.property('firstName', 'lastName')
});

var tom = Person.create({
  firstName: "Tom",
  lastName: "Dale"
});

tom.get('fullName')

Il est à préciser que le résultat fullName est mis en cache pour éviter de recalculer à chaque fois les propriété et que ce cache est automatiquement invalidé lorsqu’une des propriétés en dépendance change.

A présent, passons en revu les différentes briques de l’application.

Application & Router

Commençons par l’élément central de l’application, à savoir l’objet Application qui est responsable de relier toutes les briques du MVC ensemble.

window.App = Ember.Application.create();

L’élément application permet de définir un namespace qui contiendra par la suite l’intégralité des objets composants Ember afin d’en limiter le scope. Lors de la création, le template root aussi appelé “application template” est rendu. Voici une spécificité de Ember, l’application ne possède qu’une seule page dont le contenu sera modifié en fonction de l’état courant.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<!DOCTYPE html>
<html lang="en">
  <head>
    <title>Ember.js first step</title>
  </head>
  <body>
    <script src = "js/jquery.js"></script>
    <script src = "js/handlebars.js"></script>
    <script src = "js/ember.js"></script>

    <script type="text/x-handlebars" data-template-name="application">
      <header>
        <h1>MVC app</h1>
      </header>

      <div>
       {{outlet}}
      </div>

      <footer>
        contact me
      </footer>
    </script>

  </body>
</html>

L’élément {{outlet}} sert de point d’ancrage pour d’autres templates qui seront injectés par le router en fonction de la navigation de l’utilisateur dans l’application. On peut bien évidemment créer plusieurs outlet en les nommant, par exemple pour un footer dynamique:

1
{{outlet footerOutlet}}

On peut ensuite mapper une URL à un outlet spécifique et à son contrôleur. Ci-dessous, on configure le comportement de footerOutlet sur l’URL ‘/’ pour être managé par ‘footer’. Cela correspond à une convention qui indique à Ember qu’il doit binder cette zone avec footerController et footerView.

1
2
3
4
5
6
7
8
9
10
window.App.Router : Ember.Router.extend({
  root: Ember.Route.extend({
    index: Ember.Route.extend({
      route: '/',
        connectOutlets: function(router, event) {
        router.get('applicationController').connectOutlet('footerOutlet',’footer’);
       }
    })
  })
})

Je ne rentre pas plus dans les détails d’implémentation car l’API du composant Router est en train de subir quelques changements avec l’arrivée de la version 1.0.

La documentation est en pleine mise à jour et peut être trouvée ici .

View & Templating

La partie vue est généralement considérée comme l’interface utilisateur de l’application et se base sur l’association d’un template et d’un controleur au niveau du routeur.

1
2
3
4
5
6
7
window.App.viewTest = Ember.View.create({
  templateName: 'test-template',
  viewName: "viewTest",
  click: function(evt) {
    alert("viewTest was clicked!");
  }
});

1
2
3
<script type="text/x-handlebars" data-template-name="test-template">
The name of the view is <strong>{{view.viewName}}</strong>
</script>

Fini la concaténation de string pour générer du html (c’est vraiment mal), Ember utilise le système de templating Handlebars dont Yehuda Katz est également l’auteur. La création de ce moteur avait pour but d’améliorer certains aspect de Mustache.js.

Pour citer les améliorations majeures, on trouve:

●     La précompilations des templates pour de meilleures performances.

●     Ajout des fonctions helpers qui permettent de décorer un attribut.

Les valeurs affichées dans le template sont directement ‘bindées’ à celle du modèle. Ce qui se traduit par une mise à jour du template automatique au moindre changement dans le modèle.

Model

La partie modèle correspond aux structures de données de l’application et est responsable de la  notification de tout élément l’observant pour connaitre son état courant. Tous les éléments du modèle héritent de Object comme vu précédemment avec le système de classe.

En plus des computed properties, le type Object supporte le data binding pour partager des propriétés et l’observation de propriété pour être notifié lorsque une valeur change.

Voici un exemple :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
window.App.Person = Ember.Object.extend({
  firstName: null,
  lastName: null,
  fullName: function() {
    var firstName = this.get('firstName');
    var lastName = this.get('lastName');
    return firstName + ' ' + lastName;
  }.property('firstName', 'lastName')
});

var person = Person.create({
  firstName: "Mac",
  lastName: "Gyver"
});

person.addObserver('fullName', function() {
  alert(‘Le nom et/ou le prénom à été modifié”);
});

person.set(lastName, "Intosh"); // observer will fire

Il est ainsi facile d’enrichir son modèle côté client et d’ajouter des traitements lors de l’interception d’événements.

Controller

Le contrôleur contient la logique associée aux actions de l’utilisateur effectuées sur la partie vue.

Cette couche n’est pas spécialement novatrice, il est cependant bon de savoir qu’il existe des contrôleurs spécialisés dans la gestion de collection. Cela représente un des principaux use case, voici comment afficher une liste facilement.

1
2
3
4
window.App.listController = Ember.ArrayController.create();
$.get('people.json', function(data) {
MyApp.listController.set('content', data);
});

On peut par la suite facilement relié une vue à la collection contenu dans le contrôleur.

1
2
3
{{#each window.App.listController}}
 {{firstName}} {{lastName}}
{{/each}}

Ember-data

Jusqu’a présent, nous n’avons pas réellement abordé le sujet de la communication avec le serveur. Dans un premier temps, il est possible d’adopter le pattern ActiveRecord en ajoutant dans chaque objet du modèle des méthodes CRUD qui réalisent des requêtes Ajax via JQuery pour communiquer avec le serveur. Mais cette démarche se révèle vite fastidieuse et peu performante car il faut synchroniser soi-même les données à la main, gérer le cache pour ne pas harceler le serveur bref on se retrouve rapidement à développer un ORM en javascript…

C’est là qu’intervient le projet Ember-Data qui se propose de gérer tout la persistance de votre application. Pour l’instant c’est un projet à part entière, mais il devrait être intégré a la release 1.0 de Ember. Son but est donc de créer un ORM côté client pour décorréler le code applicatif client de la partie serveur, le but ultime étant de pouvoir remplacer le backend sans impacter le code client.

On retrouve donc les fonctionnalités usuelles d’un ORM :

●     gestion des méthodes CRUD

●     un système de transaction

●     un système de cache

●     synchronisation automatique avec validation et merge

L’architecture s’appuie sur une couche d’adapteurs / serialiseurs responsables de la communication avec les API serveur. Le projet est assez jeune et n’est pas encore prêt pour la production au dire de ses développeurs, je ne l’ai pas personnellement testé au delà du use case nominal mais il est assez prometteur.

Conclusion

En ce moment la concurrence est rude du côté de la jungle des frameworks MVC, il est donc essentiel de voir en quoi Ember.js se différencie de ses opposants. N’ayant pas de réelle expérience avec d’autres frameworks MVC javascript mon jugement peut manquer d’objectivité, cependant je pense que Ember est un des frameworks les plus riches qui existe actuellement pour réaliser des “single page application” complexes.

Selon moi voici ses points forts :

●     Grâce à son composant Router, il peut gérer différents états.

●     Il possède un système de binding puissant.

●     Ember n’est pas qu’une bibliothèque, mais un framework riche amenant son architecture.

●     Et enfin Ember-data qui sera une avancée importante pour la persistance.

Espérons que le passage en 1.0 permettra de stabiliser le projet qui subit régulièrement de gros changement. Si cet article vous a intéressé et que vous souhaitez aller plus loin avec les frameworks MVC je vous conseille ces ressources:

http://blog.remarkablelabs.com/2012/11/11-emberjs-resources-to-get-you-started

http://coding.smashingmagazine.com/2012/07/27/journey-through-the-javascript-mvc-jungle

http://blog.stevensanderson.com/2012/08/01/rich-javascript-applications-the-seven-frameworks-throne-of-js-2012/

Share
Categories: Frameworks Tags: , , ,