Tuesday, September 7, 2010

Using Soy instead of PHP or JSP

Traditionally, I have used PHP to create the basic template for bolinfest.com, but I never felt good about it. The mixture of presentation and content made my PHP files hard to organize, and having my URLs end in .php was embarrassing (and would be a pain to set up redirects for if I ever wanted to change them).

Nevertheless, PHP was dead simple to setup with Apache on Linux, and it was a convenient way to include a standard header and footer, along with a little logic to highlight the navigation tab for the page that was currently being displayed. At the same time, I found it annoying to duplicate the setup on Windows, which meant that I often ended up editing the files directly on the server rather than developing locally, checking into version control, and checking out on the server. It just encouraged bad habits all around.

Fortunately, I eliminated this problem over the weekend by creating a dead simple web server that works with Closure Templates. For now, I'm calling it soyweb (Soy is another name for Closure Templates), and it is available as an experimental feature of plovr. (You can download the latest version of plovr/soyweb from its Google Code site.)

Because Closure Templates are written in Java, so is my web server, which is fairly easy to do with the HttpServer class introduced in Java 1.6. Instead of having to set up a Windows service, I can run the following command to serve a directory of Soy files as HTML:
java -jar plovr.jar soyweb --dir DIRECTORY_OF_SOY_FILES
Each Soy file that is served by soyweb must have a template named .base that does not take any parameters. Currently, plovr.com is being served using soyweb, so you can see the Soy templates that power the web site in the repository.

A file such as docs.soy is served via both http://plovr.com/docs and http://plovr.com/docs.html. Personally, I have been linking to the version with the .html extension, but I can see where it may be desirable to not use any extension at all, so soyweb supports both. In either case, I am no longer exposing the underlying technology used to serve the site via the file extension.

As Soy supports specifying compile time global variables, I have decided to expose this feature via a JSON config file. This appears to be more flexible than Soy's file format for globals, as the config file for soyweb will turn a JSON list into a SoyListData and a JSON map into a SoyMapData. (Currently, comments are not allowed in the config file, but as soon as the fix for bug 212 is released for gson, I will upgrade plovr to allow comments in config files.) The use of globals has already proven useful as I use one set of values when developing locally, and another set of values when developing in production.

By default, soyweb recompiles all Soy files on every request, which is extremely convenient for development. (In reading about node.js, it sounded like I would have to restart Node every time I edited a Soy file, which would be unacceptable for development. Nevertheless, I am very excited about the future of Node, and would love to see more Node/Closure integration down the road.) Obviously, dynamic recompilation is not a good feature for soyweb in production, so there is a --static flag that can be used to disable it. The other flag of interest is --port, which can be used to specify which port soyweb runs on (defaults to 9811), so I use the following command to run soyweb in production to serve plovr.com:
java -jar plovr.jar soyweb --dir www --static --globals prod-globals.js
Because I am running Apache, I had to set up the following proxy from port 80:
  ProxyRequests Off

<Proxy *>
Order deny,allow
Allow from all

ProxyPass / http://plovr.com:9811/
ProxyPassReverse / http://plovr.com:9811/
Be aware that I produced that by a series of guess-and-check operations while reading the Apache documentation on mod_proxy, so it is quite possible I am not using best practices in that respect.

1 comment:

  1. Reading your Closure book now. I have to amid it is quite a thick one!