4
votes

I am working on a MarionetteJS web application with several different functional areas. For example, one is "dashboard", another is "groups", and a third is "events", each with their own specific routes.

E.g.

  • /dashboard#show
  • /groups#list
  • /groups#show/123
  • /events#v/9876/attendees

etc.

In the past I have used Marionette modules to segment the main Application object into pieces that can be started and stopped. This was useful when the application being developed is a 100% single page app - meaning I can load up an MVC route from the server (such as http://example.com/dashboard) and kick off the appropriate Marionette component(s). http://example.com/groups would kick off a different set of Marionette component(s)

In its current state (at the time of this writing, 2.4.2) Marionette has deprecated the Module component in favor of other module loading mechanisms. In the example given above, is it still possible using a different architectural approach to segment a Marionette Application into pieces to be triggered independently? The way I see it, I could:

  1. Create multiple Marionette.Application() objects and load them each independently of one another.
  2. Utilize Marionette.Object() and extend the Marionette.Application() object into sub-components somehow.
  3. Create a "main" router that listens for root urls (events/, dashboard, groups) and then create "sub-routers" that extend this to offer more functionality.
1

1 Answers

5
votes

I would go with the following approach using CommonJS modules. These sub applications or modules cant be started or stopped, but they provide a nice separation.

app.js

var Marionette = require('backbone.marionette');
var _ = require('underscore');

module.exports = Marionette.Application.extend({
    initialize: function() {
        this._modules = [];
    },

    addModule: function(name, klass ,options) {
        var module = new klass(options);

        this._modules[name] = module;
    }
});

layout.js

var Marionette = require('backbone.marionette');

module.exports = Marionette.LayoutView.extend({
    el: '#app',

    regions: {
        header: '[data-region="header"]',
        main: '[data-region="main"]'
    }
});

groups/index.js

var Marionette = require('backbone.marionette');

var Router = require('./router');

var Group = require('./model/group');
var GroupCollection = require('./model/group_collection');

var GroupListView = require('./list/collection_view');
var GroupDetailView = require('./detail/group_view');

module.exports = Marionette.Object.extend({
    initialize: function(options) {
        this.container = options.container;

        this.router = new Router({
            controller: this
        });

        this.groups = new GroupCollection();
    },

    groupList: function() {
        var groupListView = new GroupListView({
            collection: this.groups
        });

        this.groups.fetch();

        this.container.show(groupListView);
    },

    groupDetail: function(id) {
        var groupDetailView = new GroupDetailView({
            model: this.groups.findWhere({id: id})
        });

        this.container.show(groupDetailView);
    }
});

groups/router.js

var Marionette = require('backbone.marionette');

module.exports = Marionette.AppRouter.extend({
    appRoutes: {
        'groups': 'groupList',
        'groups/:id': 'groupDetail'
    }
});

main.js

var Backbone = require('backbone');

var Application = require('./app');
var MainLayout = require('./layout');

var HeaderApp = require('./header');
var GroupsApp = require('./groups');

var app = new Application();
var layout = new MainLayout();

app.addModule('header', HeaderApp, {
    container: layout.getRegion('header')
});

app.addModule('groups', GroupsApp, {
    container: layout.getRegion('main')
});

app.start();

Backbone.history.start({
    pushState: true
});

I omitted the models, collections and views from this example, but i hope you get the gist.

Your app is an extended Marionette application where you can register modules on.

Each module lives in it's own folder with an index.js file that serves as the entry point for the module. In this file you build a Marionette object that serves as the controller for your module.

Each module has it's own router with the Marionette object in the index.js file as it's controller.

Add models, collections, views and templates as you please. For communication between modules you could use Backbone.Radio.

Finally you bootstrap your app, main layout and modules in main.js, and build it with browserify or webpack.

Disclaimer

I didn't invent this architecture myself, but at the moment I don't remember the original source.