Rendr: Run your Backbone apps in the browser and Node

AirbnbEng
The Airbnb Tech Blog
6 min readApr 10, 2013

By Spike Brehm

You may remember our blog post back in January that first introduced Rendr, our library for running Backbone.js apps seamlessly on both the client and the server. We originally built Rendr to power our mobile web app, and in the post we explained our approach and showed some sample code.

We’ve been blown away by the response from the community. With 80,000 hits to the original blog post and a constant stream of questions and comments on Twitter, it quickly became clear that we’d stumbled upon a Zeitgeist. Many developers shared the same pain points with the traditional client-side MVC approach: poor pageload performance, lack of SEO, duplication of application logic, and context switching between languages.

The number one question we received went something like this: “When will u release Rendr???”

Well, we’ve up and done it — Rendr is now an open source project, and you can check out the code over at github.com/rendrjs/rendr. A good place to start is the sample app: github.com/rendrjs/rendr-app-template. It provides some minimal boilerplate for a Rendr app, fashioned as “GitHub Browser”, a little app that consumes the public GitHub API. Rendr is meant to work with any RESTful API, so please give it a try with your API of choice. If you come up with something you’d like to show off, send it to us at @rendrjs and we’ll host a little gallery of Rendr apps.

Server-side Backbone at HTML5DevConf

Last week at HTML5DevConf I got a chance to speak on Rendr. [Check out the slides]() for some more context on Rendr. The talk was also recorded, but the video isn’t ready quite yet. If you want to see it sooner rather than later, let the conference organizers know by asking nicely to @html5devconf. I’ll update this post when the video’s live.

The conference was great; there were phenomenal speakers, and there was a lot of useful tips on how to build modern, maintainable JavaScript apps.

Indeed, there were no less than two other talks on server-side Backbone. Tim Branyen showed previewcode and Lauri Svan showed backbone-serverside, both prototypes that demonstrate sharing Backbone code between the client and the server. We got to meet up over lunch and compare approaches, and it was really interesting to see how similar our code was, with a few important differences.

For example, both Tim and Lauri chose AMD via RequireJS for modules, while I chose CommonJS via Stitch. Also, we all used Express as a web server, but they patched Backbone.Router or Backbone.History to route and handle server-side requests, whereas I created separate ClientRouter and ServerRouter classes that delegate to Express or Backbone.Router, and a separate routes file. Tim and Lauri chose to stub out jQuery on the server using Cheerio; I opted to avoid DOM abstractions on the server in favor of strict string-based templating.

What’s important, though, is that we all arrived at this approach after struggling with the drawbacks of a traditional client-side Backbone app. And I’m sure we’re not the only ones: there must be a number of developers who’ve hacked on similar approaches, just like Bones. There’s an opportunity here to combine our efforts and work towards a library that we can all use and extend to fit our needs.

Design Goals

Here is the simple set of design goals which are guiding Rendr’s development.

Write application logic agnostic to environment.

Indicating what data to fetch, which template to render, which route to match, how to transform a model’s data — this logic can and should be abstracted from specific implementation details as much as possible.

Library, not a framework.

In true Backbone style, Rendr strives to be a library as opposed to a framework. A small collection of base classes which can be built upon is easier to adopt and maintain than a batteries-included web framework. Solve the problem at hand without imposing unneeded structure on the application.

Minimize code like if (server) {…} else {…}.

If your application has a bunch of conditions that look like this, then it means you’re doing something wrong. It’s a sign of a leaky abstraction. Of course, sometimes it’s necessary to know which environment you’re in, but that logic should be consolidated and abstracted away as much as possible. Which leads us to…

Hide complexity in the library.

There are a few really tricky problems that need to be tackled to achieve these other goals. The complexity of the solutions should be hidden in the library, keeping the application code clean, but remain accessible when it’s time to override core behaviors.

Talk to a RESTful API.

Backbone is great at integrating with a RESTful API. Let’s follow that convention, keeping the data source separate from Rendr itself. It should be possible to write adapters for different data sources, such as Mongo, CouchDB, Postgres, or Riak, but the library shouldn’t impose structure on your model layer.

No server-side DOM.

We prefer string-based templating over using a DOM on the server because DOM implementations are slow, and, well, because it feels hacky. You shouldn’t need a DOM to render HTML. However, I’m curious how this will change though once WebComponents become commonplace.

Simple Express middleware.

Express is the de facto Node.js web server. Rendr should fit with Express convention, exposing a few simple middleware. A nice effect of this is that you can tack on Rendr routes onto any existing Express app, or have Rendr and non-Rendr content served from the same codebase as necessary.

The Evolution of Rendr

I’d love to see Rendr evolve to become even more modular, pulling out components like the routing, templating, and view classes into separate modules, leaving the minimal set of glue required to sanely build a Backbone app that runs on the client and server. With a bit of work, it may even be possible to decouple Rendr from Backbone itself, allowing it to work with other client-side MVC libraries.

While you can easily use the code we’ve released to build a production-quality app (if you don’t mind getting your hands a bit dirty), our intention for Rendr isn’t for it to be the next [Rails, Meteor, Ember, Backbone]. Instead, we want to explore the problem of isomorphic JavaScript applications and stimulate discussion in the community.

To that end, we’ve been talking with @mde, who maintains the Geddy project, the first and most complete web framework for Node.js. Geddy is more of a Rails-style server-side MVC framework, but Matt shares our vision for JavaScript apps that can run on both sides. We’re looking at what it would take to allow Geddy to take advantage of Rendr’s approach. What primitives and abstractions do we need to build applications that can seamlessly render views, route requests, and fetch data in both environments?

Rendr, Decaffeinated

Coming from Rails, we Airbnb engineers were initially smitten with CoffeeScript. We’ve found it increases our productivity and lets us avoid some of the more verbose parts of JavaScript. Thus, Rendr has been written mostly in CoffeeScript. But heeding the advice of the broader Node.js community, we’re in the process of converting it over to plain-jane JavaScript. This will make it easier for more people to adopt and contribute, avoiding fragmentation. Interesting side note: when we show off Rendr to people from the Node.js community, they choke on the CoffeeScript without fail, but the Backbone community and front-end developers in general seem to prefer CoffeeScript.

Open Source at Airbnb

Rendr comes hot on the heels of the announcement of Chronos, the open source replacement for cron built by our data-infrastructure team.

We’ve also released a few JavaScript projects that are borne out of our efforts building web apps here at Airbnb.

Infinity.js is a small library for managing infinite scroll. It’s like UITableView for the web.

Polyglot.js is a browser- and Node.js-compatible library for handling internationalization. The secret-sauce of Polyglot.js is its handling of pluralization rules for non-English languages. For example, Chinese and Korean have just a single form, whereas Russian, Czech, and Polish have three forms.

We’ve got a few more exciting open source projects coming through the pipeline, so keep an eye out! Follow @AirbnbEng and @rendrjs for updates.

And, as always, we’re hiring talented engineers to work all over our stack: frontend, backend, search, trust & safety, machine learning, data-infrastructure, analytics — you name it.

Check out all of our open source projects over at airbnb.io and follow us on Twitter: @AirbnbEng + @AirbnbData

Originally published at nerds.airbnb.com on April 10, 2013.

--

--

AirbnbEng
The Airbnb Tech Blog

Creative engineers and data scientists building a world where you can belong anywhere. http://airbnb.io