How to share Backbone.js models with node.js

I've been building a node.js app for a project for a while now, and I just redesigned the architecture of the client (a single-page HTML5 app) to use Backbone.js. The problem that I needed to solve was the ability to reuse common data models and business logic both on the client and the server, so that I wouldn't have to have two different representations of the same model. I like to have all my parsing and serialization logic "nearby" so if the over-the-wire format changes, there's no hunting involved.

One of the real beauties of server-side JavaScript is that you're able to reuse business logic on the client. Mundane tasks like input validation, need to at least happen on the server. Traditional Web 1.0 apps did these entirely on the server, but modern web apps often need to do it both on the server and client since a web-based UI might not be the only consumer. If you're offering an API for third-party developers, then it's handy to offer single logic for validation to avoid inconsistencies.

Backbone.js requires Underscore.js, so both need to be made available to modules in the node.js environment. Luckily, both are CommonJS-aware, so adding the directory containing underscore.js to the require path as part of your bootstrapping process is a good idea:

require.paths.unshift('../vendor/underscore');

The following code generates the client-side source from a model object that could contain both server and client-side logic. It looks for an __exports__ property in the constructor. ClientModelFactory will only serialize properties defined by __exports__ either through the exact name or a regular expression matching the constructor's own properties or those of its prototype.

To use this technique, you should include both Underscore.js and Backbone.js in your HTML page as usual. You'll also want to include the generated client-side model that is generated by calling ClientModelFactory.makeAll(). For development, you could have a URL handler at /js/models.js that calls this and returns the generated content. Obviously, for production, doing the generation offline and integrating it with part of your build process makes much more sense.

This approach blurs the line between client and server. In the war against cruft, this is a plus for me.


Read my other posts.