Restarting Marionette applications

Over the course of the last couple months, I’ve been using Derick Bailey’s superb Marionette framework for Backbone.js to build the new version of Neatline. Marionette sits somewhere in the hazy zone between a library and a framework – it’s really a collection of architectural components for large front-end applications that can be composed in lots of different ways. I use Marionette mainly for the core set of message-passing utilities, which make it easy to define interactions among different parts of big applications – pub-sub event channels, command execution, request-response patterns, etc. I’ve come to completely rely on these structures, and can’t really imagine writing non-trivial applications without them anymore.

The only big kink I’ve encountered was in the Jasmine suite. Since almost all of the integration-level test cases mutate the state of the application (trigger routes, open/close views, etc.), I needed to completely burn down the app and re-start it from scratch at the beginning of each test to ensure a clean slate. The top-level Marionette Application has a start method that walks down the tree of modules and runs the initializers. As it exists now, though, start can only be called once during the lifecycle of the application, and does nothing if it’s called again later on.

I was getting around this by defining independently-callable init methods for all of my modules and wiring them up to the regular Marionette start-up system:

And then manually calling all of the init methods in my Jasmine beforeEach()‘s to force-restart the application:

This is icky – I have to exactly recreate a specific start-up order that’s automatically enforced in the application itself by before: and after: initialization events. And it introduces lots of opportunities for false-negatives – if you add a module, and forget to explicitly start it in the test suite, everything falls apart.

Really, I wanted to just re-call Neatline.start() before every test. I realized tonight, though, that the application object can be tricked into restarting itself by (a) stopping all of the modules and (b) resetting the top-level Callbacks on the application:

Much cleaner. Assuming all state-holding components are started in the initializers, this has the desired effect of completely rebooting the application.

I’d imagine this is a pretty common issue – is there any philosophical reason for the prohibition against re-calling Application.start() more than once?

  • Sergey Kurdin

    David, I am trying to restart Marionette app followed by your exmaple but I have error when I do:

    myApp.initCallbacks.reset();

    I could not find initCallbacks anywhere in Marrionette Applicationo object, is it something you added?

    I want to restart my App if user change language, so I can re-render elements, etc.

    • dclure

      Hi Sergey,

      You’re right, I believe this changed in Marionette a couple months ago and I forgot to update the blog post. It’s now `_initCallbacks` with the underscore, not just `initCallbacks`.

      I updated the gist in the post – let me know if this works!

      Best,
      David

      • Sergey Kurdin

        David, thanks for replaying. Changing to _initCallbacks helps, no JS error right now.

        I needed to restart app to change language for views, so I ended with code like this:

        var wcApp = new Backbone.Marionette.Application();
        $.extend(wcApp, { restart: function() {
        // restart wcApp here
        wcApp.start(wcApp.settings.toJSON());
        wcApp.sideMenusView.rerender();
        wcApp.toolbarView.rerender();
        wcApp.chatView.rerender();
        }
        });

        wcApp.on(‘initialize:before’, function(options) {
        $.i18n.setLocale(wcApp.settings.get(‘langid’));
        });

        wcApp.on(‘start’, function(options) {
        // app start here
        });

        I wonder, if I do that as modules (which is a good idea anyway) will module.stop(); take care of destroying view elements or I need to take care of this? What I did in my views, I have rerender method, where I do $element.remove() and then call this.render().

  • Many thanks for this. I am just getting into Marionette, and I am sitting here trying to write some tests wondering how the hell I am supposed to tear down my Marionette App? I’m surprised there isn’t a MyApp.stop() for this specific testing scenario where you need to tear everything down after some tests run.

    • dclure

      Yeah, that would be handy. We should just add it! I’ll see if I can rustle up some time to send a little PR.