Introduction to Marionette.js
"All your backbone's belong to Marionette.js"
META
"Backbone.Marionette is a composite application library for Backbone.js that aims to simplify the construction of large scale JavaScript applications.
It is a collection of common design and implementation patterns found in the applications that we have been building with Backbone, and includes pieces inspired by composite application architectures, event-driven architectures, messaging architectures, and more."
~ 68kb unminified
~ 23kb minified
~ 6kb gzip
Why do we care?
-
Scale applications out with modular, event driven architecture
- Sensible defaults, such as using Underscore templates for view rendering
- Easy to modify to make it work with your application's specific needs
- Reduce boilerplate for views, with specialized view types
- Build on a modular architecture with an Application and modules that attach to it
- Compose your application's visuals at runtime, with Region and Layout
- Nested views and layouts within visual regions
- Built-in memory management and zombie killing in views, regions and layouts
- Built-in event clean up with the EventBinder
- Event-driven architecture with the EventAggregator
-
And much, much more...
Why Do I Care?
- Modular
- Scalable
- Maintainable
- Testable
Design Patterns
"All Of This Has Happened Before And Will Happen Again"
- Composite
- Event Driven
- Command/Execute (Pub/Sub)
- Request/Response
What does it provide?
- application
- application.module
- approuter
- callbacks
- collectionview
- commands
- compositeview
- configuration
- controller
* this presentation's focus
- functions
-
itemview
- layout
- region
- regionmanager
- renderer
- requestresponse
- templatecache
- view
REQUIRE Setup
require.config({ paths : { 'backbone' : './backbone', 'jquery' : './jquery', 'marionette' : './marionette', 'underscore' : './underscore' }, shim : { 'backbone' : { deps : ['jquery', 'underscore'], exports : 'Backbone' }, 'jquery' : { exports : 'jQuery' }, 'marionette' : { deps : ['jquery', 'underscore', 'backbone'],
exports : 'Marionette' }, 'underscore' : { exports : '_' } } });
Backbone vs marionette
- present a typical backbone way ( or my way at least ) of implementation or discuss the typical pitfalls I ran into
- present a Marionette solution and code example
My Application
- Non existant support in Backbone
- Left to OO Javascript implementation
- Controller and Application tightly coupled
- Application configuration harder than in it should be
-
Rudimentary initialize method to start the application and set up route driven architecture
Marionette.Application
- addInitializer() method for convenience
- Application level events ( onInitializeBefore, onInitializeAfter, onStart )
- They all get access to the configuration options passed into App.start() and addInitializer() methods
-
Also Regions, Layouts, etc.
Example
var App = new Marionette.Application({ onInitializeBefore : function(options) { // execute before initializers... }, onInitializeAfter : function(options) { // execute after initializers },
onStart : function(options) { // execute after initializers & events }
});
App.addInitializer(function(options) {
// code to be run on application init
});
Application.Module
- Auto start from App.start()
- Added seperation of concerns and basic module structure which can be used with or without AMD support
- `this` keyword bound to module object scope
- Hierarchical module loading ( Mod, Mod.Thing )
- start and beforeStart events
- startWithParent flag for suspending module execution until explicitly started by Mod.start()
- Getter provided from App with App.module('moduleName')
- stop and beforeStop events provided to help with memory management and other module level cleanup items
- callback definition for easy access to... ( ModuleName, AppName or parent ModuleName, Backbone, Marionette, jQuery, Underscore, Custom Arguments
Example
App.module("MyModule", function(MyModule, App, Backbone, Marionette, $, _){
// Private Data And Functions // -------------------------- var myData = "this is private data"; var myFunction = function(){ console.log(myData); } // Public Data And Functions // ------------------------- MyModule.someData = "public data";
this.someFunction = function(){ console.log(MyModule.someData); } });
App.module('MyModule').addInitializer(function() {});
My Controller
- To coupled with the router
- To involved in View memory management
Example
_.extend(Controller, { someRouteController : function() { var views = []; // check that our router is ready // and other things... this.auth();
// destroy previous views
this.destroyViews();
// insert view, model, etc code here...
// render new views views this.renderViews(views); },
destroyViews : function() {
if (this.currentView) { while (this.currentView.length > 0) { this.currentView.pop().destructor(); } } },
renderViews : function(views) { this.currentView = views; for (var i = self.currentView.length - 1; i >= 0; i--) { this.currentView[i].render(); } },
auth : function() { // simply code that needs to be asserted before anything else can run } });
Marionette.Controller
- State mediator object
- Can be utilized inside modules or app level
- Convenience hooks for AppRouter
- Standard initialize() method
- built in event aggregator can be utilized using the listenTo() method
- close method and onClose event
Example
// define a controller var MyController = Marionette.Controller.extend({ initialize: function(options){ this.stuff = options.stuff; }, doStuff: function(){ this.trigger("stuff:done", this.stuff); } }); // create an instance var c = new MyController({ stuff : "some stuff" });
// use the built in EventBinder c.listenTo(c, "stuff:done", function(stuff){ console.log(stuff); }); // do some stuff c.doStuff();
My Router
-
Just basic Backbone.Router's
-
Usually helps drive a good deal of the application
Example
var IndexRouter = Backbone.Router.extend({
initialize : function(options) {
this.app = options.app;
},
routes : {
'' : 'tilesBackbone',
'tilesbackbone' : 'tilesBackbone'
},
tilesBackbone : function() {
this.app.tilesBackbone();
}
});
AppRouter
- Extends Backbone.Router
- Provides a hook for your Marionette.Controller
- Allows the addition of routes at runtime ( MyRouter.appRoute('/foo', 'bar' )
Example
MyRouter = Backbone.Marionette.AppRouter.extend({ controller : MyController, appRoutes : { "some/route": "someMethod" },
// standard backbone routes routes : { "some/otherRoute" : "someOtherMethod" }, someOtherMethod : function(){ // do something here. } });
My View
- Standard Backbone.View, but usually extended from a baseView with common functionality
- baseView.destructor() provided that would try and do memory cleanup for that View ( could be overridden )
- memory management wasn't automatic, required execution ( usually automated by my Controller )
- Decoupled from other views by using a Mediator Object which allowed pub/sub and cleanup methods
Example
var Tile = BaseView.extend({ el : '.tile-wrap',
events : { 'click .btn' : 'flip' },
subscriptions : { // add pub/sub subscriptions here... },
initialize : function(options) { _.bindAll(this); this.templar = options.templar; }, flip : function(e) { this.$el.find('.tile').toggleClass('flipped'); }, render : function() { this.templar.render({ path : 'tile', el : this.$el, data : {} }); } });
ItemView
-
Extension of Backbone.View
-
Works with Backbone Models and Collections
-
Reduces boilerplate of having to JSONify your models & collections
-
serializeData method for custom serialization for your ItemView
-
template method can be configured for use with other Templating solutions other than _.template's
-
Setup and breakdown methods ( onBeforeRender, onRender, onBeforeClose, and onClose )
- ui pragma to set up references to needed DOM elements
Example
Backbone.Marionette.ItemView.extend({
tagName : 'fieldset',
ui: {
checkbox : 'input[type=checkbox]'
},
onRender: function() {
if (this.model.get('selected')) {
this.ui.checkbox.addClass('checked');
}
}
});
let's look @ Code...
Conclusions
- Pros
- I like Marionette's continuation of Backbone's extend/use if needed policy
- Sets up consistency and better memory management
- Reduces common Backbone boilerplating
- Good documentation and examples
- Pretty well adopted and supported ( v1.1.0 came out 6 days ago )
-
Cons
- Still MV*, Controller is a little ambiguous still
- Still not a framework
Questions
Resources
http://marionettejs.com/
https://github.com/marionettejs/backbone.marionette/tree/master/docs
books and more...
Presentation Slides
http://slid.es/ianqueue/marionettejs
Contact
https://github.com/ianqueue
@ianqueue
MarionetteJS
By ianqueue
MarionetteJS
A brief presentation on what Backbone.Marionette tries to help us fix with large Backbone applications...
- 3,606