Improve this doc

Template Engine Wrappers

SocketStream supports a wide variety of client-side template engines through the use of third party modules.

If you can't find a module for your preferred templating language, it's easy to create your own. This page guides you through the process, using the ss-hogan module (a wrapper for Twitter's Hogan library), as a reference.

Let's look at the key file in this module, engine.js:

/* engine.js */

// Hogan Template Engine wrapper for SocketStream 0.4

var fs = require('fs'),
    path  = require('path'),
    hogan = require('hogan.js');

module.exports = function(ss, config) {

  // Send Hogan VM to the client
  var clientCode = fs.readFileSync(path.join(__dirname, 'client.js'), 'utf8');
  ss.client.send('lib', 'hogan-template', clientCode);

  return {

    name: 'Hogan',

    // Opening code to use when a Hogan template is called for the first time
    prefix: function() {
      return '<script type="text/javascript">(function(){var ht=Hogan.Template,t=require(\'socketstream\').tmpl;'
    },

    // Closing code once all Hogan templates have been written into the <script> tag
    suffix: function() {
      return '}).call(this);</script>';
    },

    // Compile template into a function and attach it to ss.tmpl
    process: function(template, path, id) {

      try {
        var compiledTemplate = hogan.compile(template, {asString: true});
        return 't[\'' + id + '\']=new ht(' + compiledTemplate + ');';
      } catch (e) {
        return e;
      }

    }
  }
}

Here prefix and suffix are called once each. In between those calls, process gets called for every file this template engine handles.

In this example, the wrapper is compiling templates on the server side, then passing the compiled templates to the client. The prefix and suffix functions wrap the compiled templates inside a <script> tag, so that the templates are ready to use when the page loads.

Selecting a Formatter (optional)

Formatters are used to transform the contents of each template before it is sent to the template engine.

By default SocketStream selects a formatter based on the template file's extension. Most of the time this will prove useful (e.g. automatically transforming .jade files to HTML), but occasionally you will need to overwrite this behavior (e.g. if you want the .jade file to be sent to the template engine as-is).

Simply add a selectFormatter function to your engine:

/* lib/engine.js */

exports.init = function (root, config) {
  // ...
  return {
    // ...
    selectFormatter: function (path, formatters, defaultFormatter) {
      return defaultFormatter;
    },
    // ...
  }
};

The formatter that selectFormatter returns is the formatter that SocketStream will use to render the template before passing it to the template engine's process function. If you return false, SocketStream will pass the contents of the file directly to the template engine without any pre-processing.

Tips

When building your own template wrapper be sure to consider the following points:

Try to pick the best trade off between performance and overall bytes sent to the client, bearing in mind it's not uncommon for a large app to have 50 or more templates.

If a client-side VM is needed to render the template (as is normally the case) you should include the client code within your module and tell SocketStream to server it using the ss.client.send() command (see Hogan example above).