We are the Dev Teams of
  • brands
  • ebay_main
  • ebay
  • mobile
<
>
BLOG

Node.js with Express and Closure Templates

by Ingo Bartel
in Tutorials

The express web application framework provides a set of template engines (jade as default, EJS and JSHTML) however, I got used to Closure Templates and was playing around with a bunch of Node.js plugins to get this working.

Obviously, a lot of Closure Template plugins are outdated or no longer worked with the current Node.js version. The most used plugin for Closure Templates is soynode. This plugin works as intended, however, it is not well-integrated into express out of the box. If you want to stick to the express way to render a template, you need to make small changes to your Node.js main application.

In this post, I show how to create a node+express application from scratch and add the closure templates as the template rendering engine. You'll need to have Node.js and Express working (I used Node.js 0.11.6 and Express 3.3.8)

If you haven’t installed Node.js and use Linux, I suggest cloning the Git repo and compiling it on your own, since the managed repos (at least for Ubuntu-based systems) are often slow to update the Node.js package. Another option is to use one of the various Personal Package Archive solutions but that’s not the way I prefer and compiling Node.js is very easy.

The Express installation comes with a standalone script located in the bin directory of your Node.js installation. Running express -V in your shell should not result in an error and give you the version number instead.

Start off by creating a basic skeleton, installing the soynode plugin and removing the default engine (jade):

express example-app
cd example-app
npm install
npm install soynode --save
npm remove jade --save

Now open your app.js file in your favorite editor (i prefer Nodeclipse or Sublime Text) and add the following dependencies:

var os = require('os');
var soynode = require('soynode');

followed by the configuration for soynode:

soynode.setOptions({
	outputDir: os.tmpdir(), 
	uniqueDir: true, 
	allowDynamicRecompile: true, 
	eraseTemporaryFiles: true
});

For information on configurating soynode, see the GitHub repo. It’s important to adjust your configuration before compiling the templates.

Next, you need to change the view engine of express to “.soy”. Look for the line

app.set('view engine', 'jade');

and replace this line with the following block:

app.set('view engine', '.soy');

var soyRenderer = function(_path, options, callback) {
    var templatePath = _path.replace(path.normalize(this.root + '/'), '');
    templatePath = templatePath.replace('.soy',path.sep + options['function']);
    templatePath = templatePath.split(path.sep).join('.');
    callback(null, options.soynode.render(templatePath, options));
};

app.engine('.soy', soyRenderer);
app.use(function(req, res, next) {
    res.locals.soynode = soynode;
    next();
});

Explanation: The soynode doesn’t include an express rendering engine, so the very simple function soyRenderer will do the trick. Be aware that this function is pretty plain, so if you want to have a more robust and safe function you should add some love here. The renderer is required to ensure that you can later use the render method on the response object by specifiying a template and passing parameters.

Express allows you to put in customized renderers with the app.engine(‘.soy’, soyRenderer). Since the custom soyRenderer function needs to have access to the soynode, you need to append a very small middleware to the express application. That is done by adding the app.use() block.

Now you need to modify the current behavior of starting the server. Replace the following lines

http.createServer(app).listen(app.get('port'), function(){
  console.log('Express server listening on port ' + app.get('port'));
});

with

soynode.compileTemplates('views', function(err) {
    if (err) throw err;
    http.createServer(app).listen(app.get('port'), function(){
        console.log('Express server listening on port ' + app.get('port'));
    });
});

Explanation: The web server needs to be started after the templates are compiled/loaded. In this example, I used compileTemplates, which means that all “.soy” files inside the views folder are compiled when the server starts or “.soy” files are changed (controlled via configuration). Compilation is done with the module’s bundled Java version SoyToJsSrcCompile.jar. If you prefer to compile templates on your own, you could also consider using “loadCompiledTemplates” instead. The callback is called when compilation/loading is complete – the web server should be started if no errors occured.

Those are all the changes needed in the application, now you need to make a minor change in the examples route “index”. Open the file index.js in the routes folder and exchange the render line with

res.render('index', {'function': 'welcome', title: 'Express' });

Explanation: In the routes/index.js the render method needs to have also the “function” passed as a mandatory parameter. That’s the actual soy function inside the given template. About the template name it’s very important to know that the compiled templates no longer have any knowlege about the path structure the uncompiled soy templates were in. Instead, closure templates use a namespace, which could be considered as a path as well. The render method however looks for name.render engine extension, which means you have to specify a correct template path located in the views folder. To make closure templates and express happy, you need to define the package name as if it were a tree-like path. For example:

// template is located in views/index.soy
// {package index}
// {template .welcome}
res.render('index', {'function': 'welcome', title: 'Express' });

// template is located in views/dashboard/index.soy
// {package overview.index}
// {template .show}
res.render('dashoard/index', {'function': 'show', ...your fancy model here });

Now you can create the index closure template inside the “views” folder. You can safely remove the existing index.jade and layout.jade and create a new file called “index.soy” with the following content

{namespace index}

/**
 * @param title
 */
{template .welcome}
<!DOCTYPE html>
<html>
  <head>
    <title>{$title}</title>
    <link rel='stylesheet' href='/stylesheets/style.css' />
  </head>
  <body>
    <h1>{$title}</h1>
    <p>Welcome to {$title}</p>
  </body>
</html>
{/template}

Now you’re ready to go! Go back to your example-app root and start the server by calling node app. Open your browser and you should see the default Express page. To verify that everything is working, you can change something in the index.soy without restarting the server. The server will automatically compile the soy template and you should see your changes when you refresh the browser.

For the full working application, visit https://github.com/ibartel/nodejs-express-closure-templates.

nodejs, express, google closure templates

?>