Comment bien commencer avec Backbone.js / Marionette.js ?

Je vais passer le pourquoi du comment Backbone.js et Marionette.js, qui est pour moi un couple JS qui fonctionne très très bien pour le dev côté front-end. Si vous êtes arrivé ici, je considère que vous en connaissez un minimum sur ces FW, au moins les concepts de Model Collection View Router propres à Backbone.js.

Le but de cet article est de vous montrer ce que j'utilise comme structure pour débuter une application avec Marionette.js. Ça vous aidera sûrement pour débuter avec ce framework, bien que la doc officielle soit déjà pas mal foutue.

Faut-il utiliser Require.js ?

La grande question quand on commence à vouloir structurer son application JavaScript et qu'on veut bien faire, comprendre, comme dans la plupart des tutos bien balèzes. Je suis passé par là, j'ai testé, et finalement j'ai tout pété. Pourquoi faire compliqué quand on peut faire simple.

Donc, non vous n'êtes pas obligé : pour une application vraiment grande (mais vraiment hein), vous pouvez commencer à en ressentir le besoin. Un peu comme Gmail qui vous charge d'abord le module pour les mails, puis les contacts, le chat, etc. Mais sur une application Marionette, avec les librairies quivontbien, les classiques jQuery(UI) + 3, 4 librairies JS histoire ne pas ré-inventer la roue, quand vous aurez tout assemblé et minifié, vous n'aurez plus qu'un fichier JS et quelques libs chargées via CDN dans 90% des cas. Donc dans 90% des cas Require.js est inutile.

De plus Marionette utilise deux concepts pour vous aider à structurer votre code et instancier l'ensemble : l'application et les modules. Si vous avez fait un peu de Django par exemple, ça vous ne sera pas étranger. L'application sera votre bootstrap, votre chef d'orchestre, alors que vos modules seront en fait vos mini-applications. Donc d'emblée, Marionette vous pousse au découpage et découplage, bien !

L'objet Marionette.Application

Regardons ensemble ce que nous pouvons faire avec :

var myApp = new Backbone.Marionette.Application();

L'instancier... euh ok

myApp.addInitializer(function(options){
  // do useful stuff here
  var myView = new MyView({
    model: options.someModel
  });
  myApp.mainRegion.show(myView);
});

myApp.addInitializer(function(options){
  new myAppRouter();
  Backbone.history.start();
});

Ajouter des initializer... aaah pas mal. C'est simple, mais efficace. Quand votre application démarre, elle appelle les initializer, et dans l'ordre d'ajout s'il vous plaît. Si vous avez des outils, contrôleur, routeur, etc, à initialiser quand l'application se lance, c'est ici, tout simplement.

Et comment lance-t-on l'application ? Et les options que je vois dans tes callbacks elles sortent d'où ?

Taratataaa, rien de plus simple

myApp.start({foo:"bar"})

Et pour les cas vraiment complexes où vous auriez un bootstrap par dessus ce bootstrap, vous pouvez même modifier les options juste avant les initializer ou lancer des actions.

myApp.on("initialize:before", function(options){
  options.moreData = "Yo dawg, I heard you like options so I put some options in your options!";
});

Vous remarquerez la méthode on() qui sert à inscrire une callback à un événement donné. Vous retrouvez ce principe dans Backbone.js et Marionette.js, ainsi que son inverse listenTo() qui sera souvent plus approprié dans une vue.

Vous avez accès à trois d'événements depuis l'application :

  • initialize:before / onInitializeBefore : levé juste avant que les initializers soient lancé
  • initialize:after / onInitializeAfter : levé juste après la fin initializers
  • start / onStart : au vrai début de l'application, donc après les initializers, et les événements des initializers.

Non aux variables globales

Avant de passer à la suite, récapitulons ce que donne notre application, encapsulé dans une IIFE et ajoutée dans un namespace qui sera notre seule variable globale.

MyNamespace.myApp = function(Backbone, Marionette, _, $, Handlebars, etc) {
  var myApp = new Backbone.Marionette.Application();

  myApp.addInitializer(function(options){
    // do useful stuff here
    // like maybe configure Handlebars
    ...
  });

  myApp.addInitializer(function(options){
    // inside an initializer `this` is the app
    this.router = new MyNamespace.Router();
    Backbone.history.start();
  });

  return myApp;

}(Backbone, Marionette, _, $, Handlebars, etc);

MyNamespace.myApp.start(someOptions);

Ça sera tout pour cette partie. Je vais découper le tuto en 3 ou 4 partie vu le temps que ça me prend.