2012-07-06 3 views
16

Sto iniziando un'applicazione javascript su larga scala con Marionette. Un'applicazione Marionette ha un concetto di moduli applicativi e RequireJS viene utilizzato anche per rompere il codice in moduli,Backbone Marionette e RequireJS Modules

Attualmente ho questo per l'inizio della mia domanda:

require([ "jquery", "underscore", "backbone", "marionette" ], 
function ($, _, Backbone, Marionette) { 
    $(function() { 

     App = new Marionette.Application(); 
     App.addInitializer(function(options) { 
      App.addRegions({ 
       mainArea: "#mainArea" 
      }); 
     }); 

     App.on("start", function() { 
      // done starting up, do stuff here 
     }); 

     App.start(); 
    }); 
}); 

Se volessi aggiungere una vista sarebbe Faccio qualcosa di simile al seguente in un file?

require([ "jquery", "underscore", "backbone", "marionette" ], 
function($, _, Backbone, Marionette) { 

    App.module("FirstView", function(FirstView, App, Backbone, Marionette, $, _) { 
     return Marionette.ItemView.extend({ 
      //define view stuff in here 
     }); 
    }); 

}); 

io non sono sicuro di come avrei avuto questo codice da eseguire in realtà, ogni aiuto è molto apprezzato

risposta

23

moduli di Marionette sono destinate ad essere una semplice alternativa al RequireJS (e altri) formati di moduli. Non consiglierei usarli insieme, come indicato nel wiki:

https://github.com/marionettejs/backbone.marionette/wiki/AMD-Modules-vs-Marionette's-Modules

+0

ha un senso. Grazie! Userò RequireJS, perché presumo che se usassi i moduli Marionette dovrei incollare tutti i miei file applicativi in ​​tag script in testa come in BBCloneMail, sto cercando di evitare di farlo. –

+1

Non è consigliabile utilizzare più tag di script. BBCloneMail non è un esempio di come farlo. :) I progetti reali hanno costruito passi concatenanti e minisiti. r.js fa per i moduli requirejs, o può essere fatto con uno qualsiasi di un certo numero di altri strumenti come la pipeline di asset di Rails o grunt.js, o molti altri strumenti. –

+2

Ecco un collegamento di aggiornamento per l'utilizzo di Marionette con RequireJS. (Il repository github è stato spostato.) Https://github.com/marionettejs/backbone.marionette/wiki/Using-marionette-with-requirejs –

4

IMHO mi piace differire dal punto di vista sopra indicato "moduli di marionette sono destinate ad essere una semplice alternativa al RequireJS (e altri) formati di modulo. "

Mi piace disegnare un confronto tra i moduli Require.js e i moduli Marionette.js con i concetti di assemblaggio e spazio dei nomi di C#. I moduli di Marionette.js ci aiutano a raggruppare le definizioni di vari elementi costitutivi in ​​base alle funzionalità, mentre Require.js può essere utilizzato per caricare/iniettare dipendenze.

Ancora una volta, questo è il mio punto di vista/comprensione (basato sulle discussioni con David Sulc sul suo libro "Strutturare il codice backbone con RequireJS e moduli Marionette"), che ha aiutato nella mia implementazione. In un modo possiamo utilizzare Marionette.js e Require.js insieme come descritto di seguito.

L'esempio seguente è una piccola app Library Manager (esempio) che può essere trovata online @https://github.com/srihari-sridharan/LibraryManagement. Il codice seguente (omettendo bit e parti non significativi) crea l'oggetto dell'applicazione e restituisce l'elenco dei libri dopo l'inizializzazione. Si prega di trovare qui - https://github.com/srihari-sridharan/LibraryManagement/blob/master/app/js/app.js

define([ 
    'marionette', 
    'modules/config/marionette/regions/dialog'], function (Marionette) { 

    // Create the application object 
    var LibraryManager = new Marionette.Application(); 

    // Add regions to the application object 
    LibraryManager.addRegions({ 
     //Header 
     headerRegion: "#header-region", 
     //Main 
     mainRegion: "#main-region", 
     //Footer 
     footerRegion: "footer-region", 
     //Overlay Dialog 
     dialogRegion: Marionette.Region.Dialog.extend({ 
      el:"#dialog-region" 
     }) 
    }); 

    // Subscribe to Initialize After event. 
    LibraryManager.on('initialize:after', function() { 
     if(Backbone.history){ 
      require(['modules/books/booksModule', 'modules/about/aboutModule'], function(){ 
       Backbone.history.start();  
       if(LibraryManager.getCurrentRoute() === ''){ 
        LibraryManager.trigger("books:list"); 
       }      
      }); 
     } 
    }); 

    // Return the application object. 
    return LibraryManager; 
}); 

Poi si definiscono i/sottomoduli modulo in base alla funzionalità. Questo avrà anche un router specifico per il modulo e collegherà i controller e gestirà i percorsi. Si noti la richiesta di chiamata ai controller. Questo codice è presente in https://github.com/srihari-sridharan/LibraryManagement/blob/master/app/js/modules/books/booksModule.js

define(['app'], function (LibraryManager) { 
    // Define a new module for Books - BooksModule 
    LibraryManager.module('BooksModule', function (BooksModule, LibraryManager, Backbone, Marionette, $, _) { 

     BooksModule.startWithParent = false; 

     BooksModule.onStart = function() { 
      console.log('Starting BooksModule.'); 
     }; 

     BooksModule.onStop = function() { 
      console.log('Stopping BooksModule.'); 
     }; 

    }); 

    // Define a new module for a Router specific to BooksModule 
    LibraryManager.module('Routers.BooksModule', function (BooksModuleRouter, LibraryManager, Backbone, Marionette, $, _) { 

     BooksModuleRouter.Router = Marionette.AppRouter.extend({ 
      appRoutes: { 
       'books': 'listBooks', 
       'books(?filter:=criterion)': 'listBooks', 
       'books/:id': 'showBook', 
       'books/:id/edit': 'editBook' 
      } 
     }); 

     var executeAction = function (action, arg) { 
      LibraryManager.startSubModule('BooksModule'); 
      action(arg); 
      LibraryManager.execute('set:active:header', 'books'); 
     }; 

     var API = { 
      // This is where we are using/referring to our controller 
      listBooks: function (criterion) { 
       require(['modules/books/list/listController'], function (ListController) { 
        executeAction(ListController.listBooks, criterion); 
       }); 
      }, 

      showBook: function (id) { 
       require(['modules/books/show/showController'], function (ShowController){ 
        executeAction(ShowController.showBook, id); 
       }); 
      }, 

      editBook: function (id) { 
       require(['modules/books/edit/editController'], function (EditController) { 
        executeAction(EditController.editBook, id); 
       }); 
      } 

     }; 

     // Navigating routes. 
     LibraryManager.on('books:list', function() { 
      LibraryManager.navigate('books'); 
      API.listBooks(); 
     }); 

     LibraryManager.on('books:filter', function(criterion) { 
      if(criterion){ 
       LibraryManager.navigate('books?filter=' + criterion); 
      } 
      else{ 
       LibraryManager.navigate('books'); 
      } 
     }); 

     LibraryManager.on('book:show', function (id) { 
      LibraryManager.navigate('books/' + id); 
      API.showBook(id); 
     }); 

     LibraryManager.on("book:edit", function(id){ 
      LibraryManager.navigate('books/' + id + '/edit'); 
      API.editBook(id); 
     }); 

     LibraryManager.addInitializer(function() { 
      new BooksModuleRouter.Router({ 
       controller: API 
      }); 
     }); 
    }); 

    return LibraryManager.BooksModuleRouter; 
}); 

Infine abbiamo le definizioni per le nostre opinioni, modelli e controllori. Queste definizioni saranno legate agli oggetti modulo/sotto modulo.

Il codice di visualizzazione è mostrato di seguito. Guarda i metodi .extend(). Sono assegnati alle variabili associate al modulo secondario BooksModule.List.View. https://github.com/srihari-sridharan/LibraryManagement/blob/master/app/js/modules/books/list/listView.js

define(['app', 
     'tpl!modules/books/list/templates/layout.html', 
     'tpl!modules/books/list/templates/panel.html', 
     'tpl!modules/books/list/templates/none.html', 
     'tpl!modules/books/list/templates/list.html', 
     'tpl!modules/books/list/templates/listItem.html'], 
    function (LibraryManager, layoutTemplate, panelTemplate, noneTemplate, listTemplate, listItemTemplate) { 

     LibraryManager.module('BooksModule.List.View', function(View, LibraryManager, Backbone, Marionette, $, _) { 

      View.Layout = Marionette.Layout.extend({ 

       template: layoutTemplate, 

       regions:{ 
        panelRegion: '#panel-region', 
        booksRegion: '#books-region' 
       } 

      }); 

      View.Panel = Marionette.ItemView.extend({ 
       // More code here! 
      }); 

      View.Book = Marionette.ItemView.extend({     
       // More code here! 
      }); 

      var NoBooksView = Marionette.ItemView.extend({ 
       template: noneTemplate, 
       tagName: "tr", 
       className: "alert" 
      }); 

      View.Books = Marionette.CompositeView.extend({ 
       // More code here! 
      }); 
     }); 
    return LibraryManager.BooksModule.List.View; // Return the definition. 
}); 

Il codice del controller è mostrato di seguito. Questo viene chiamato dal codice in booksModule.js. La definizione del controller è allegata al modulo secondario BooksModule.List.

define(['app', 'modules/books/list/listView'], function (LibraryManager, View) { 

    LibraryManager.module('BooksModule.List', function (List, LibraryManager, Backbone, Marionette, $, _) { 

     List.Controller = { 

      listBooks: function (criterion) { 

       require(['common/views', 'entities/book'], function (CommonViews) { 

        var loadingView = new CommonViews.Loading(); 
        LibraryManager.mainRegion.show(loadingView); 

        var fetchingBooks = LibraryManager.request('book:entities'); 
        var booksListLayout = new View.Layout(); 
        var booksListPanel = new View.Panel(); 

        require(['entities/common'], function (FilteredCollection) { 

         $.when(fetchingBooks).done(function (books) { 
          // More code here! 
          }); 

          if(criterion){ 
           filteredBooks.filter(criterion); 
           booksListPanel.once('show', function() { 
            booksListPanel.triggerMethod("set:filter:criterion", criterion); 
           }); 
          } 

          var booksListView = new View.Books({ 
           collection: filteredBooks 
          }); 

          booksListPanel.on('books:filter', function (filterCriterion) { 
           filteredBooks.filter(filterCriterion); 
           LibraryManager.trigger("books:filter", filterCriterion); 
          }); 

          booksListLayout.on("show", function(){ 
           booksListLayout.panelRegion.show(booksListPanel); 
           booksListLayout.booksRegion.show(booksListView); 
          }); 

          booksListPanel.on('book:new', function() { 

           require(["modules/books/new/newView"], function (NewView) { 
             // More code here! 
            }); 

            LibraryManager.dialogRegion.show(view); 
           }); 
          }); 

          booksListView.on('itemview:book:show', function (childView, model) { 
           LibraryManager.trigger("book:show", model.get('id')); 
          }); 

          booksListView.on('itemview:book:edit', function(childView, model) { 
           require(['modules/books/edit/editView'], function (EditView) { 
            // More code here! 
            LibraryManager.dialogRegion.show(view); 
           }); 
          }); 

          booksListView.on("itemview:book:delete", function (childView, model) { 
           model.destroy(); 
          }); 

          LibraryManager.mainRegion.show(booksListLayout); 

         }); 

        }); 

       }); 

      } 

     } 

    }); 

    return LibraryManager.BooksModule.List.Controller; // Return the definition. 
}); 

require.js Così moduli e moduli marionette possono coesistere. I seguenti sono i vantaggi.

  • Organizzazione molto più pulita del codice sorgente e separazione più chiara dei problemi.
  • I metodi di avvio e arresto del modulo forniscono la possibilità di inizializzare e ripulire gli oggetti.
  • Quando modellate funzionalità e sottofunzionalità come moduli e sottomoduli, abbiamo un controllo più granulare su cosa risiede nella memoria e cosa non dovrebbe.
  • Inoltre, la definizione del modulo può essere suddivisa su più file.

Si prega di inviare i vostri pensieri. Grazie per aver letto.

PS: Sulla base della precedente punto di vista, si prega di trovare le modifiche al tuo esempio qui sotto:

require([ "jquery", "underscore", "backbone", "marionette" ], 
function($, _, Backbone, Marionette) { 
    App.module("FirstView", function(FirstView, App, Backbone, Marionette, $, _) { 
     FirstView.View = Marionette.ItemView.extend({ 
      //define view stuff in here 
     }); 

     return FirstView.View; 
    }); 
});