connect-jade-client
connect-jade-client is Connect middleware for serving compiled Jade templates to clients with maximum flexibility and minimum hassle.
Installation
Install via npm:
npm install connect-jade-client
Required Settings
At a minimum, three settings must be provided to the middleware:
var connectJadeClient = require("connect-jade-client");
...
app.use(connectJadeClient({
source: "/full/path/to/your/client/jade/directory",
public: "/full/path/to/your/site/public/directory",
prefix: "/url/prefix/for/client/views"
}));
In other words,
source
is the root directory for your client-side Jade template files,public
is the root directory for your site's public files, andprefix
is the path underpublic
that identifies a relevant request.
Details
Assume we have this example site structure.
/usr/local/mysite/
index.js
client/
views/
FirstView.jade
SecondView.jade
SecondView/
DateView.jade
TimeView.jade
ThirdView.jade
public/
...
Configuration
The connect-jade-client middleware is configured in index.js
like so:
app.use(connectJadeClient({
source: path.join(__dirname, "client", "views"),
public: path.join(__dirname, "public"),
prefix: "/js/views"
}));
Compilation
On startup, the middleware searches for all file ending in ".jade" under the source
root directory. It compiles all of the files into a hash table of function objects, where the key names correspond to the source structure. In the example, the resulting table looks like this:
FirstView: function(args) {...}
SecondView: function(args) {...}
DateView: function(args) {...}
TimeView: function(args) {...}
ThirdView: function(args) {...}
}
The value associated with each key is the compiled template function.
Note that to match the source structure, SecondView
also defines the DateView
and TimeView
functions as properties. This namespacing is supported to an arbitrary depth.
Request / Response
The middleware looks for incoming HTTP requests where the path begins with the prefix
setting and ends in ".js". It generates a JavaScript response that creates a hash table of the compiled templates on the client. In the example, the generated file/response for http://mysite.com/js/views.js
looks like this:
var T = {};
T.FirstView = function(args) {...};
T.SecondView = function(args) {...};
T.SecondView.DateView = function(args) {...};
T.SecondView.TimeView = function(args) {...};
T.ThirdView = function(args) {...};
window.Templates = T;
Example Use
Assume that the contents of the SecondView files are as follows:
- SecondView.jade:
div Date and Time
- SecondView/DateView.jade
.date The date is #{date}.
- SecondView/TimeView.jade
.time The time is #{time}.
These (rather contrived) templates could be used in a (similarly contrived) Backbone View like this:
var TimeView = Backbone.View.extend({
render: function() {
return Templates.SecondView.TimeView(time: moment().format("MMM Do YY"));
}
});
var DateView = Backbone.View.extend({
render: function() {
return Templates.SecondView.DateView(date: moment().format("hh:mm:ss"));
}
});
var SecondView = Backbone.View.extend({
render: function() {
this.$el.append(new DateView().render());
this.$el.append(new TimeView().render());
return this;
}
});
Multiple Apps
Because you can request any subset of templates using the corresponding path, it's easy to support multiple client-side apps. Given a source
structure like this:
/usr/local/mysite/
client/
views/
FirstApp/
FooView.jade
SecondApp/
BarView.jade
ThirdApp/
BazView.jade
...
The subset of templates corresponding to each app can be requested with the URLs:
http://mysite.com/js/views/FirstApp.js
http://mysite.com/js/views/SecondApp.js
http://mysite.com/js/views/ThirdApp.js
Similarly, the template(s) for a single view could be requested with the URL:
http://mysite.com/js/views/FirstApp/FooView.js
Alternate Template Format
In the example, sub-templates of the SecondView template are stored in a corresponding subdirectory. The middleware also supports a custom format where all templates are stored in the same file, with comments used to identify the sections. The comment format is:
//-- TemplateName.jade
Note that the comment must begin with the string //--
followed by at least one space, and end with the string .jade
. All text up to the first identifier comment is the template associated with the name of the file itself; all text following an identifier comment is the template associated with the filename specified in the comment. Only one level of nesting is supported.
In the example, the templates in the SecondView subdirectory could instead be included in SecondView.jade as follows:
div Date and Time
//-- DateView.jade
.date The date is #{date}.
//-- TimeView.jade
.time The time is #{time}.
Optional Settings
-
global
The name of the client-side public variable. (string)default: Templates
Include the global
setting to specify an alternate name for the templates variable.
-
jadeOptions
Options passed to the Jade compiler. (object)default: { client: true, compileDebug: false, debug: false, pretty: true }
Any options you specify will be merged into the default options.
-
reload
Search for and recompile templates on every request. (boolean)default: false
By default, the middleware will only generate a new JavaScript file if it doesn't exist, or if the file date is earlier than any of the source .jade files it references. This means that during development, it won't pick up changes to .jade files made after the middleware was initialized. Set the reload
setting to true
to have it rebuild the templates on every request.
reload: (process.env.NODE_ENV === "development")