mjackson/mach

Template rendering

Closed this issue · 2 comments

Was thinking about what a mach.render call could look like for rendering templates... have you thought about it much? Like providing an interface that taps into https://github.com/visionmedia/consolidate.js so a use could specify a template language and use it with mach.render calls... etc.

This feels a little out of scope for mach.

The goal of mach is to provide a better foundation for writing HTTP servers than http.js. Originally, I was hoping we could circumvent http.js entirely, possibly using something like creationix/node-web, but that hasn't happened yet.

However, I do think that most developers need something higher-level like what you're talking about. I'm just not a fan of the Express approach of bundling everything together in one module.

In my ideal scenario, this higher-level framework would be a little more declarative, like Rails or Sinatra. So you would declare a directory that holds your templates and then use a simple render("myTemplate") to render it. Basically it would do the job of the controller in the Rails MVC model, and it would export a mach app.

var myController = new Controller({
  templatesDir: './templates',
  get: function (params, query) {
    return this.render('myTemplate', { message: query.message });
  }
});

mach.serve(myController.app);

This was working for me. A middleware:

var path = require('path')
var mach = require('mach')
var Promise = require('bluebird')

var renderFile = Promise.promisify(require('jade').renderFile)

module.exports = function (app, viewsDir, isCache) {
  if (!viewsDir) throw new Error('No view directory specified')
  if (!isCache) isCache = false

  return function (request) {
    request.locals = { cache: isCache } // create locals object on request

    request.render = function (view, locals) {
      if (locals) for (var local in locals) request.locals[local] = locals[local] // merge locals
      return renderFile(path.join(viewsDir, view), request.locals)
        .then(function (html) { return mach.html(html) })
    }

    return request.call(app)
  }
}

What I like is:

  1. I can add locals anywhere down the stack and have them available when I finally run it. I found this extremely helpful in Express.
  2. With consolidate (not added) I can get support for a lot of templating engines with caching for those engines that don't natively support it.

What I don't like:

  1. Augmenting the request object when its really about the response. Hence why I was thinking about some sort of mach.render thingy.

I think I'll continue to play and push out a module at some point. Doesn't seem to need to be that complex. Wanted to share to get any feedback.