14

Has anyone found a good solution for developing templates for backbone.js that can be used on the server and the client?

This is really desirable with the backbone.js history stack, as users can share and link to real urls in the browser location bar, and the node.js server can render the page on first page view, while using the same templates in the client to rebuild pages on subsequent page views.

This would also provide an ideal output for both users and for search engines that spider the links and won't have to parse or execute javascript to see a fully rendered and working page.

Updated with more info:

Two possible approaches to this appear to be:

1) bones - https://github.com/developmentseed/bones

Bones has some quirks to install and currently needs an old version of node and npm.

2) capsule - https://github.com/andyet/capsule

I haven't tried this yet, but it seems similar. I'd be interested if anyone has interest with either of these projects.

9 Answers 9

4

I'm currently working on a framework named "onecode" that does what you asked for. Currently it lacks documentation, but I have a working project based on it, so it could work for you too. I'm also looking for contributors.

Here's how it works. Almost all code is shared between client and server, including models and views.

  1. On server, you create a REST API where you define business rules, security, db operations, all that you cannot trust to a client.
  2. This API is used both from clients (using standard Backbone Ajax calls) and from server itself when the page is first requested (directly, using overridden $.ajax method).
  3. When a client requests a page, server creates all needed models and views, makes direct requests to API and renders HTML. Moreover, it remembers all data that came from API calls and which HTML elements correspond to which Views.
  4. Model/View code, HTML and Data is served to client. Here, HTML is fully rendered and functional, so even if the user turned off JavaScript, he can click links and browse the website (he will not get any dynamic features of course). But, if the Javascript is enabled, all Models and Views are recreated and re-binded to DOM nodes automatically in background, not making user wait.
  5. After that, the application works like a single-page app, requesting only data (json) from the same API, rendering templates on client.

This means that:

  1. You write presentation and dynamic code only once.
  2. First requested page is served and shown to user lightning fast, doesn't require to wait for all scripts to load and run, just HTML/CSS.
  3. Next pages are also very fast because only raw data is requested, templates are rendered on client. You can also make it visually attractive, not usual page reload. You can even play music while user browse the website.
  4. Search engines and Social Networks love you.

The architecture forces some sane requirements which will make you a better developer. Something like:

  1. Separate, well-defined API needed for server actions and business rules.
  2. No global variables.
  3. Views are treated more strictly than in general Backbone, more like stackable UI components.
  4. Clear separation between HTML rendering and dynamic behaviors.

A very simple example can be found in the source tree. I use Backbone as a basis for Models and Views, and Browserify deliver js package to client.

In my project I use inline templates with EJS as a templating engine. This has advantage of keeping HTML and code (I use CoffeeScript) in the same place. But the framework is capable of packaging templates from external files, with other templating engines like Jade. Please, see a templating example on how it could be done.

Please let me know if you are interested this approach, maybe it'd push me to start writing docs for it.

Sign up to request clarification or add additional context in comments.

Comments

1

I haven't used it for node, but I've used mustache pretty extensively for backbone.js and been pleased with the results, and it has a port to use it with node as well.

http://mustache.github.com/

1 Comment

Mustache is a templating engine that will work anywhere you can run javascript - you can plug it into node and backbone if you're not happy with the underscore templating. Ideally what I'm looking for would go further to use the backbone routers, models and views on the server to spit out an identical page that the client can assemble after a pushstate action.
1

In terms of choosing a template language, you can pretty much take your pick with any js-based templating language, including Underscore Templates, Mustache or Handlebars - it's trivial to set up templates in a publicly accessible path that your Node.js application also reads when the content is generated server-side.

My personal favourite is Jade, which comes out of the box with Express - it enforces a very simplistic, expressive coding style.

You can find a good write-up of how to link together Backbone.js and Express here (using Jade as the template language).

Most of the examples tend to be how to set up a RESTful application which renders entirely client-side (and is not what you're really after).

However if you get your web app rendering in Express from templates in a publicly accessible folder (I would recommend keeping views separate - preprocess your templates and hand the html over to your views, so you keep the templates specific) then you'll be able to load them from Backbone.js too, and handle changes using Backbone.js's history stack.

Comments

0

You could use JSDOM to render your page with node.js as follows

// specify a catch all route
app.get('/namespace/*', function (req, res, next) {
  // load the dom
  jsdom.env({
    html: html,
    src: src,
    features: {
      FetchExternalResources: false,
      ProcessExternalResources: false 
    },
    done: function (err, window) {
      // overwrite Backbone's sync method with a server-side one
      window.Backbone.sync = sync
      window.$(function () {
        window.Backbone.history.start({ silent: true })

        // load requested url
        var matched = window.Backbone.history.loadUrl(req.originalUrl.substr(1))
        if (matched) // if matched: return resulting html
          res.end(window.document.innerHTML)
        else
          next()
      })
    }
  })
})

Therefor you also have to specify the following variables

var sync = function(method, model, options, error) {
  // your server side sync method
}

var html = fs.readFileSync(path.join(__dirname, 'views/index.htm'), 'utf-8')
var src = [
  fs.readFileSync(path.join(__dirname, 'public/javascripts/jquery.js'), 'utf-8'),
  fs.readFileSync(path.join(__dirname, 'public/javascripts/underscore.js'), 'utf-8'),
  fs.readFileSync(path.join(__dirname, 'public/javascripts/backbone.js'), 'utf-8'),
  fs.readFileSync(path.join(__dirname, 'public/javascripts/your-backbone-stuff.js'), 'utf-8')
]

Unfortunately I didn't found a solution to duplicate the created window/document object for reuse.

Also this solutions is only suitable for e.g. search engines because it lacks the client-side mapping from Backbone Views to there corresponding DOM nodes.

Comments

0

Try https://github.com/flatiron/plates

Works great in both environments, is DSL free and has a clean API

3 Comments

How do you bind data to attributes of elements?
where('attribute').insert('key');
You should open another question if you need more specifics on Plates.
0

Try jsrender at https://github.com/BorisMoore/jsrender.

It is a rewrote from jQuery tmpl, and does NOT requires jQuery or any DOM. It is self-contained in a single file and the author keep it very fresh.

jsrender is a string-replacement engine for templating. We use it for both dynamic and static page in NodeJS. We also use it for non-HTML templates, e.g. XML, CSV, and text-based email. Although it is not in production mode yet, we have been using it for few months and the development is so far very stable.

Look at some cool demos at http://borismoore.github.com/jsrender/demos/demos.html.

At its simplest, you can do foreach loop. But if you are going expert route or be adventurous, you can have JS code running (either inlined, or passed as a function, a.k.a. helpers). Sure it is bad to have code inside presentation layer, but sometimes it don't hurt to have simple odd()/even() or nth+1 calculation in your favorite language. Just make sure you have a good understanding between layers and take the risks.

Comments

0

Node.js with nunjucks templating is working well for me because I needed non-XML templating for non-SGML web content (nunjucks allows setting the template delimiters in text templates - which is the case with jinja2 for Python on which nunjucks is a re-eng )

Comments

0

Here's a very simple example of rendering an Underscore/Backbone template in NodeJS. I've installed Underscore using NPM.

var http = require('http'),
    _ = require('underscore');

http.createServer(function (req, res) {
    var template = "<h1><%=message%></h1>"
    res.end(_.template( template, {message: "Hello world"}));
}).listen(8080, 'localhost');

Comments

0

I have tried numerous solutions, and http://ezeljs.com/ is definitely the simplest and most easy to implement. It just makes sense.

A boilerplate for Backbone projects that share code server/client, render server/client, and scale through modular architecture.

Uses Jade templates, for both the server and the client. Browserify and using a Jade transform, is definitely my preferred method for sharing templates on both the client and the server.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.