Closure Templates (aka Soy) can be used either on the server or client-side. The recommended way to use them server-side is with SoyTofu, but there is a way to use them in pure javascript on the server with our new pal, NodeJS.
Suppose we have this blog.soy template to render a simple blog post with some comments:
{namespace blog} /** * Renders a post with comments. * @param post * @param comments */ {template .postPage} <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> <html lang="en"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>blog</title> <meta name="generator" content="TextMate http://macromates.com/"> <meta name="author" content="Sean McCullough"> <!-- Date: 2009-11-28 --> </head> <body> {call .post} {param post: $post /} {/call} {call .comments} {param comments: $comments /} {/call} </body> </html> {/template} /** * Renders a Post. * @param post */ {template .post} <h2>{$post.title}</h2> {$post.body} {/template} /** * Renders a list of comments. * @param comments */ {template .comments} <h3>Comments:</h3> <ul> {foreach $comment in $comments} <li>{$comment}</li> {/foreach} </ul> {/template}
The Closure template compiler will take this input .soy file and create an output .js file that contains functions corresponding to the {template .functionName} sections above.
To compile:
java -jar SoyToJsSrcCompiler.jar --outputPathFormat templates-compiled/blog.js templates/blog.soy
The generated functions in templates-compiled/blog.js look like this:
blog.post = function(opt_data, opt_sb) { var output = opt_sb || new soy.StringBuilder(); output.append('<h2>', soy.$$escapeHtml(opt_data.post.title), '</h2>', soy.$$escapeHtml(opt_data.post.body)); if (!opt_sb) return output.toString(); };
Now, if you just try to require() this generated .js file, Node will complain because it doesn't know what soy.StringBuilder() is. We can fix that by shoehorning soyutils.js into node, of course.
First we need to make soyutils.js work with Node's require mechanism. require works in conjunction with process.mixin(), so you make soy require()-able by adding this to the bottom of soyutils.js (copied into your application code directory from the closure templates distribution):
process.mixin(exports, soy);
Then we need to require soyutils in the blog.js file (you can just paste these into the bottom of the file but it's probably better to implement this as a post-soy-compile step in a build script so you don't have to keep pasting every time you recompile the template)
var soy = require('../soyutils'); process.mixin(exports, blog);
That last process.mixin call will make the blog template functions available to other source files via require.
Now we're ready to use the soy template with our nodejs server code. You'd just require templates-compiled/blog.js and call the functions that it provides from within your event handlers (again, building on the blogging example from a previous post):
var sys = require("sys"), http = require("http"), blogTemplates = require("./templates-compiled/blog"); var handlers = { '/posts/{postId}' : { GET : function(request, response, args) { response.sendHeader(200, {"Content-Type": "text/html"}); var commentsPromise = getCommentsPromise(args.postId); var postPromise = getPostPromise(args.postId); var templateVars = {}; commentsPromise.addCallback(function(comments) { templateVars.comments = comments; }); postPromise.addCallback(function(post) { templateVars.post = post; }) var joinedPromise = join([commentsPromise, postPromise]); joinedPromise.addCallback(function() { var pageHtml = blogTemplates.postPage(templateVars); response.sendBody(pageHtml); response.finish(); }); } } } };
This is awfully clunky. I'd like to write a directory watcher that automatically compiles recently updated .soy files, appends the require and process.mixin calls, and reloads the result into Node.
Thoughts on Closure and NodeJS
I spent a little time trying to get the closure compiler to work with Node so that you could for instance, statically verify that the template function invocation parameters match up with the declared parameter types in the .soy file. Haven't gotten enough working there to blog about yet though.
I don't know if the closure compiler optimizations would help NodeJS much, but the static analysis would probably help catch a lot of easy-to-introduce but too-tedious-to-unit-test problems that crop up when you have lots of people working on the same code base.
Also, the Closure Library contains a lot of useful packages that could be applied server-side as well.
glad i found this as i have been working on the same thing.
ReplyDeleteI wonder if the main people behind NodeJS are doing this. I doubt that it can be done as a Module as it really needs to be baked into the core more.
AngularJS Training in Chennai AngularJS Training in Chennai Node.js Training in CHennai Angular 2 Training in Chennai Angular 2 Training in Chennai Node.js Training in CHennai Node.js Training in chennai MEAN Developer Training in Chennai
ReplyDeleteBackBoneJS Training in Chennai BackBoneJS Training in Chennai EmberJS Training in Chennai EmberJS Training in Chennai
Interesting Article
ReplyDeleteJavascript Training in Chennai | HTML5 Online Training
JavaScript Training Courses | Javascript Online Training | Angular 2 Training in Chennai
guaranteed search engine rankings
ReplyDeleteairlie beach tours
whitsunday private yacht charters
famous brand slogans
ppc optimization
air jordan uk
ReplyDeletelions jerseys
cincinnati bengals jerseys
cheap jordans
nhl jerseys
oakley sunglasses
under armour shoes
new york knicks
oakley sunglasses wholesale
chicago bears jerseys
harden shoes
ReplyDeleteyeezys
jordan shoes
adidas neo
michael kors outlet store
nike mercurial vapor
adidas ultra boost
adidas stan smith men
longchamp
http://www.uggoutlet.uk
oakley sunglasses
ReplyDeletenew balance shoes
supra shoes
jordan
adidas outlet store
timberland boots
michael kors outlet
birkenstock outlet
oakley sunglasses
oakley sunglasses
20185.16wengdongdong