plovr: a Closure build tool

SoyWeb Command

SoyWeb is a simple web server built into plovr for serving static content. It is analogous to using Python's SimpleHttpServer, except SoyWeb serves a Soy file by rendering a template in the file as HTML.

Motivation

Oftentimes in web development, UI designers create mocks using HTML and CSS, and then developers have to write code or create templates to produce the same HTML, but with user data. This creates a burden for both designers and developers:With the introduction of the September 2011 release of Closure Templates, it is now possible to declare list and map literals within a Soy file. As the following example demonstrates, this makes it particularly compelling to use SoyWeb for composing mocks of web UI.

Unlike other templating languages like PHP and JSP, Soy gives users just enough programming logic to eliminate duplicate HTML across pages (using template calls and loops), but not so much programming power that business logic will leak into the template.

Example: tasks.soy

Consider the following file, tasks.soy, in a directory js that defines three templates: the UI for a task list, the boilerplate for a demo page, and an instance of the task list on a demo page:
{namespace tasks}

/**
 * @param title
 * @param items
 */
{template .list}
<h1>{$title}</h1>
<div>
  {foreach $item in $items}
    <div class="{css task-item}">
      <div style="margin-left: {$item.indent * 24}px">
        {$item.name}
      </div>
    </div>
  {ifempty}
    <div class="{css tasks-complete}">
      Nothing to do!
    </div>
  {/foreach}
</div>
{/template}

/**
 * @param content
 */
{template .demoPage}
<!doctype>
<html>
<head>
  <link rel="stylesheet" href="tasks.css">
</head>
<body>
  {$content|noAutoescape}
</body>
</html>
{/template}

/**
 * This template will be rendered by SoyWeb when the user loads tasks.soy.
 * It deliberately includes dummy data so the designer can get a feel for how
 * the task list will appear with real data rather with minimal copy and paste.
 */
{template .soyweb}
{call .demoPage}
  {param content}
    {call .list}
      {param title: 'Food Shopping' /}
      {param items: [
        ['indent': 0, 'name': 'cheese' ],
        ['indent': 0, 'name': 'crackers' ],
        ['indent': 0, 'name': 'condiments' ],
        ['indent': 1, 'name': 'ketchup' ],
        ['indent': 1, 'name': 'mayo' ],
      ] /}
    {/call}
  {/param}
{/call}
{/template}
To see how the rendered template looks using SoyWeb, run the following command:
java -jar plovr.jar soyweb --dir js
Then point your browser to http://localhost:9811/tasks.html to see the task list populated with the data specified by the .soyweb template.

Now creating another template with a different set of mock data is much less work, as js/tasks2.soy can reuse the existing templates:

{namespace tasks2}

/**
 * This template will be rendered by SoyWeb when the user loads tasks2.soy.
 * This makes it possible to see how an empty task list will be rendered.
 */
{template .soyweb}
{call tasks.demoPage}
  {param content}
    {call tasks.list}
      {param title: 'Food Shopping' /}
      {param items: [] /}
    {/call}
  {/param}
{/call}
{/template}
With SoyWeb is running, the rendered version of this template can be seen at http://localhost:9811/tasks2.html.

Setting template parameters with URL query parameters

It is possible to use URL query parameters to define parameters in your Soy template by specifying the --unsafe option when starting SoyWeb. This makes it easier to see what your template will look like with different inputs. Consider the following Soy file, js/settings.soy, for a settings page that shows a user whether or not he has granted an application access to Facebook:
{namespace settings}

/**
 * @param? accessToken
 */
{template .facebook}
<div>
  {if $accessToken}
    You have granted access to Facebook.
    Your access token is <b>{$accessToken|id}</b>.
  {else}
    This application does not have access to Facebook.
    {sp}
    <button>Grant Access</button>
  {/if}
</div>
{/template}

/**
 * Demo the settings UI using SoyWeb.
 */
{template .soyweb}
<body>
  {call .facebook data="all" /}
</body>
{/template}
Normally, if you loaded settings.soy with SoyWeb, accessToken would be null, so you would see the "This application does not have access to Facebook" UI. If you wanted to see the "You have granted access to Facebook" UI, then you would have to edit facebook.soy to set {param accessToken: 'someToken' /} in the .soyweb template, and then reload the page.

It would be much more convenient to be able to edit the query parameters of the URL to SoyWeb to toggle these parameters so that:

http://localhost:9811/settings.html?accessToken=someToken
would show the "access granted" UI with whereas
http://localhost:9811/settings.html?accessToken=null
would show the "no access" UI. Fortunately, SoyWeb makes this possible when the --unsafe option is specified as follows:
java -jar plovr.jar soyweb --dir js --unsafe
When specified, SoyWeb takes each query parameter and makes a best effort to convert it to the appropriate datatype, and then passes each name/value pair as a parameter to the .soyweb template when rendering it. Here are some examples of the types of conversions that SoyWeb will do for a query string:

This option is disabled by default because it could enable a malicious user to to inject his own JavaScript into your page. For example, the user could construct the following URL that alerts gotcha when the user visits the page:

http://localhost:9811/settings.html?accessToken=%3Cscript%3Ealert('gotcha')%3C/script%3E
This particular exploit works because the author of facebook.soy used {$accessToken|id} instead of {$accessToken}, which disabled autoescaping for that variable. (Incidentally, Chrome refuses to run this JavaScript, noting: Refused to execute a JavaScript script. Source code of script found within request. in the developer tools console.)

For this reason, this feature is disabled by default and is named --unsafe to raise awareness of the security implications of enabling this option. Nevertheless, this is an effective feature for developing HTML UIs, as it makes it possible to view the interface in different states with little overhead. It is highly recommended for prototyping and for demoing to trusted users.

Options

SoyWeb has several command-line options that you can use to customize its behavior: