mi humilde opinión me gusta ser diferente del punto de vista se ha dicho "módulos de marioneta están destinados a ser una alternativa sencilla a RequireJS (y otros) formatos de módulos ".
Me gusta hacer una comparación entre los módulos Require.js y los módulos Marionette.js con los conceptos de ensamblado y espacio de nombre de C#. Los módulos de Marionette.js nos ayudan a agrupar las definiciones de varios componentes basados en la funcionalidad, mientras que Require.js se puede usar para cargar/inyectar dependencias.
Una vez más, este es mi punto de vista (basado en las discusiones con David Sulc en su libro 'Estructurar el código backbone con RequireJS y Marionette Modules'), que ha ayudado en mi implementación. De alguna manera podemos usar Marionette.js y Require.js juntos como se describe a continuación.
El siguiente ejemplo es una pequeña aplicación del Administrador de bibliotecas (muestra) que se puede encontrar en línea en https://github.com/srihari-sridharan/LibraryManagement. El código siguiente (omisión de bits y piezas insignificantes) crea el objeto de la aplicación y representa la lista de libros después de la inicialización. Por favor, encontrar aquí - 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;
});
A continuación se definen los módulos/submódulos en base a la funcionalidad. Esto también tendrá un enrutador específico de módulo y cableará los controladores y manejará las rutas. Tenga en cuenta que requieren una llamada a los controladores. Este código está presente en 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;
});
Por último tenemos las definiciones de nuestros puntos de vista, los modelos y controladores. Estas definiciones estarán vinculadas a los objetos del módulo/sub módulo.
El código de la vista se muestra a continuación. Mire los métodos .extend(). Se asignan a las variables adjuntas al submódulo 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.
});
El código del controlador se muestra a continuación. Esto se llama desde el código en booksModule.js. La definición del controlador se adjunta al submódulo 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.
});
Por lo tanto, los módulos require.js y los módulos de marionetas pueden coexistir. Las siguientes son las ventajas.
- Organización mucho más clara del código fuente y una separación más clara de las preocupaciones.
- Los métodos de inicio y parada del módulo proporcionan la provisión para inicializar y limpiar objetos.
- Cuando modela funcionalidades y subfunciones como módulos y submódulos, tenemos un control más granular sobre lo que reside en la memoria y lo que no debería.
- Además, la definición del módulo se puede dividir en varios archivos.
Por favor, publique sus ideas. Gracias por leer.
PS: Con base en lo anterior punto de vista, por favor, encontrar los cambios en el siguiente ejemplo:
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;
});
});
tiene sentido. ¡Gracias! Voy a utilizar RequireJS, porque supongo que si utilizara módulos de Marionette tendría que pegar todos mis archivos de aplicación en etiquetas de script en la cabecera, como en BBCloneMail, estoy tratando de evitar hacer eso. –
No recomiendo usar varias etiquetas de script. BBCloneMail no es un ejemplo de hacerlo bien. :) Los proyectos reales tienen pasos de construcción que concat y minify. r.js lo hace para requerir módulos, o se puede hacer con otras herramientas como Rails asset Pipeline o grunt.js, o muchas otras herramientas. –
Aquí hay un enlace de actualización para usar Marionette con RequireJS. (El repositorio github se movió.) Https://github.com/marionettejs/backbone.marionette/wiki/Using-marionette-with-requirejs –