File caching and template rendering femto-framework using mustache and some assumptions.
pup-tent is maintained by Berkeley BOP & kltm
Pup Tent is a femto-framework for template (Mustache) and static content delivery for Node.js and RingoJS (beta) web apps.
The idea is to quickly turn a pile of related JS, template, CSS, and static files into a whole coherent enough to deliver with a proper web app/routing framework, such as express.
There are two main aspects to Pup Tent. The first is searching for and synchronously caching static content on the filesystem, (including caching templates for later use), and then producing those when given the filename key (all filenames must be unique in Pup Tent). The second is aiding in using a couple of common template patterns using Mustache, examples below.
There are other examples in the tests/ directory, but a full example (without using the cache) might look like this.
Lets say you have the following files:
- static/frame.tmpl
- static/content.tmpl
- static/bar.css
- static/foo.js
- static/App.js
The file content.tmpl looks like:
{{ content }}
And the file frame.tmpl looks like:
<html>
<head>
<title>{{title}}</title>
{{#pup_tent_css_libraries}}
<link rel="stylesheet" type="text/css" href="{{{.}}}">
{{/pup_tent_css_libraries}}
{{#pup_tent_js_variables}}
<script type="text/javascript">var {{name}} = {{{value}}};</script>
{{/pup_tent_js_variables}}
{{#pup_tent_js_libraries}}
<script type="text/javascript" src="{{{.}}}"></script>
{{/pup_tent_js_libraries}}
</head>
<body>
{{ &pup_tent_content }}
</body>
</html>
The easiest way to deploy my App.js using this template and file structure could be something like:
var pup_tent = require('pup-tent')(['static']);
Set the common variables:
pup_tent.set_common('js_vars', {'name': 'foo', 'value': 'bar'});
pup_tent.set_common('js_libs', 'foo.js');
pup_tent.set_common('css_libs', 'bar.css');
Set the variables for just this page:
var targs = {content: 'bar', title: 'foo', 'pup_tent_js_libraries': ['App.js']};
var output = pup_tent.render('content.tmpl', targs, 'frame.tmpl');
This would give output like:
<html>
<head>
<title>foo</title>
<link rel="stylesheet" type="text/css" href="bar.css">
<script type="text/javascript">var foo = "bar";</script>
<script type="text/javascript" src="foo.js"></script>
<script type="text/javascript" src="App.js"></script>
</head>
<body>
bar
</body>
</html>
You might notice that some of the files are not correctly "linking" if you view your page in a web browser. On to the next section!
So far, we've just used it for some simple templating, but what if we want to use the integrated caching mechanism and use it in conjunction with something like express?
A more full-bodied example, using express as an example, might be:
var us = require('underscore');
var express = require('express');
var fs = require('fs');
var mustache = require('mustache')
var pup_tent = require('pup-tent')
var app = express();
//////
/// FOLLOW THE EXAMPLE ABOVE FOR REDACTED STUFF HERE ///
//////
// Pretty much the same as before.
app.get('/', function(req, res){
var targs = {
'title': 'Testing'
};
var output = pup_tent.render('content.tmpl', targs, 'frame.tmpl');
res.send(output);
});
// Cached static routes, using Pup Tent to easily deliver static docs.
var js_re = /\.js$/;
var css_re = /\.css$/;
var html_re = /\.html$/;
// Routes for all static cache items at top-level.
us.each(pup_tent.cached_list('flat'), function(thing){
var ctype = null;
if( js_re.test(thing) ){
ctype = 'text/javascript';
}else if( css_re.test(thing) ){
ctype = 'text/css';
}else if( html_re.test(thing) ){
ctype = 'text/html';
}
// This will skip cached templates.
if( ctype !== null ){
app.get('/' + thing, function(req, res) {
res.setHeader('Content-Type', ctype);
res.send(pup_tent.get(thing) );
});
}
});
var server = app.listen(3333, function() {
console.log('Starting at http://localhost:' +
server.address().port);
});
Since always caching can be a bit annoying when developing JavaScript/CSS heavy websites, there is also a use_cache_p() function that can be used to toggle whether Pup Tent returns to the filesystem every time or uses the internal cache. For more information about everything, see the API docs (linked at the end).
The special stack variables are:
- css_libs: will map to pup_tent_css_libraries
- js_vars: will map to pup_tent_js_variables
- js_libs: will map to pup_tent_js_libraries
The special template variables are:
- pup_tent_css_libraries: list of CSS files to use
- pup_tent_js_libraries: list of JS files to use
- pup_tent_js_variables: list of name/value objects to convert to vaiables
- pup_tent_content: meant for use in base_tmpl_name to embed one template in another
Given the right environment, the tests can be easily run from the
command line using the gulpfile.js.
gulp test
The RingoJS tests are not integrated with the Makefile (yet), but can be run from the command line interface like:
ringo -m ./lib -m ./node_modules/underscore/ -m node_modules/mustache tests/full-tmpl.js.tests