Incremental DOM with Backbone Marionette (on Rails)

Michael Tighe
500px Engineering Blog
4 min readFeb 8, 2018

--

At 500px, the majority of our client-side code is written using Backbone and Marionette, with handlebars templates. Although it has served us well so far, we’re always on the lookout for ways to improve our stack, architecture and best practices.

As a rule, we avoid directly manipulating the DOM as much as possible, preferring to update state on our view component and re-render. This makes our code a lot easier to maintain, reason about, and debug. It does, however, have some downsides; it can result in re-rendering much more of the DOM than is necessary, lose scroll positions, and “jump” or “flicker” when re-rendering (depending on the elements being rendered and how they fit into the overall page). Furthermore, our approach favours moving more logic into our templates, which starts to push the limits (and intent) of handlebars.

One solution is to apply only the changes between renders to the DOM rather than completely replacing it, using something like DOM diffing or a virtual DOM. To this end, we had a look at making use of the Incremental DOM library during one of our hack days.

Incremental DOM

Incremental DOM is a library for building templates and updating the DOM in-place as required, instead of simply replacing large chunks of it. Templates are defined in JavaScript, using a handful of methods to open and close elements and create other DOM nodes.

Clearly, this is not something you’d want to write directly, and it’s certainly not intended to be used that way. Rather, it’s designed to be a compilation target for a templating language. Once you have your template, you can update the DOM with a call to the patch method.

patch(element, function() { render(data); });

That’s all there is to it. There are two steps we need to figure out to get it up and running in our project:

  1. Update Marionette’s render method to use the Incremental DOM patch method
  2. Compile our templates into Incremental DOM

The first step is relatively straightforward, while the second is a bit more involved, especially given our particular setup. I’ll elaborate further on that shortly.

Rendering Incremental DOM with Marionette

It’s possible to override Marionette’s default render method to implement custom rendering. We were already doing this to plug in our handlebars templating, so adding Incremental DOM didn’t require much work. (Note, we’re using Marionette 2.4, so if you’re on version 3, things may look a bit different).

We need to override Marionette.Renderer.render with our new render method, and we also need to update the view’s attachElContent method to get Marionette to use the Incremental DOM patch method instead of simply replacing the DOM node.

Let’s quickly walk through what’s going on there. First, we define a function which we’ll use to override our view’s standard method of attaching rendered html to the DOM. Typically, this function takes a chunk of html generated by the render call as its parameter, but IncrementalDom.patch is expecting a function.

Next, we set up our custom render function. In order to allow us to have a mix of views using our standard handlebars templates as well as using Incremental DOM, we use a flag on the view named renderer to determine which method to use. If the view is using Incremental DOM, we override its attachElContent method and return a function which runs our Incremental DOM template with the current data. As mentioned above, this function is what ends up being passed into patch. For now, our template functions are attached to window with the prefix tmpl_. More on this later.

Compiling templates to Incremental DOM

All of our client-side templates are rendered in Rails views, on each request. This was less of a conscious decision and more a result of the evolution of our codebase over the years, and has both advantages and serious drawbacks, which I won’t get into here. We define our handlebars templates with a helper which wraps the template in a <script> tag.

There are a few libraries and templating languages out there for Incremental DOM, but none quite fit into our exact use case. As such, we opted to write a quick parser to take care of it for us, and a new helper to define our Incremental DOM templates. We write the templates in what is essentially “embedded JavaScript”. Let’s jump right to an example.

Anything in our template surrounded by <% ... %> is treated as JavaScript, and everything else is treated as html. We can also use <%= ... %> to insert the result of the enclosed JavaScript in a string or as a text node. Converting this to an Incremental DOM template, which is just a JavaScript function, is just a matter of converting html elements into Incremental DOM calls and leaving the rest, which proved to be quite straightforward.

To wrap everything up, our incdom helper passes its block into the parser, assigns the resulting JavaScript to an appropriately named function on window (in this case, window.tmpl_todo_item), and wraps it in a script tag. That’s it! At this point, we can write templates in our “embedded JavaScript” form and make full use of Incremental DOM in our Marionette views.

Wrap Up

In order to write clean, maintainable code in Marionette, we avoid manipulating the DOM anywhere outside of the render method, and prefer instead to modify view state and re-render. In order to get around some of the downfalls of this approach, we have swapped our handlebars templates and standard Marionette rendering with Incremental DOM, which updates the DOM with new changes rather than simply replacing chunks of it. We also replaced handlebars with our own form of “embedded JavaScript” templates, which allow us to use JavaScript to write much more powerful templates.

While we have yet to put this technique into production, it shows promise in solving some of the issues we have with our current methodology. In the meantime, we’re continuing to explore a number of possibilities to improve our tech stack and, in turn, our codebase.

--

--