Software Engineer, builder of webapps

Extending Underscore Templates with Partials

Back in March, I made a post on how to share Underscore templates between your client and server. Now its time to take what I talked about there to the next level to make it even easier and add some structure to your templates.

Organization and Structure

Out of the few template systems that I've looked at, hardly any of them come with a nice way of structuring template files, and thats if they use files at all in the first place. A lot of templating engines rely on embedding your templates in <script> tags in your HTML files. To me this seems really messy, disorganized, and isnt portable to be used to render things server side if you want.

Last time, we were able to take template that occupied a single file, dump it into Underscore (or LoDash if that's your preference) and be able to use that compiled template in the same way on the server and client. The trouble here is that each template, no matter how small or large, must occupy a single file. That can potentially get our of hand really quickly. It also doesnt give you an easy way of referencing templates from within other templates.

Introducing node-partials

Node-partials is an npm module that wraps Underscore/Lodash templates and allows you to define multiple partials within one template file. In doing so, this also allows us to easily reference partials from another template/partial file all together.

To install it, simply run:

npm install node-paritals

Now, lets take a look at how our template files are structured. Previously, our template files looked something like this:

<div class="some class">
    Like some HTML for example
</div>
<div class="some-val">
    This is some content of the partial
</div>

With node-partials, we would structure it like this:

## some-page-component
<div class="some class">
    Like some HTML for example
</div>
<div class="some-val">
    <%= foo %>
</div>

## text-content-partial
This is some content of the partial

Here, we have two paritals in our template file, some-page-component and text-content-partial. Each partial name is identified by using the ## followed by a space, followed by the name of your partial. Now, how do we use this?

initialization and setup

We have a template with some partials and we have the node-partials module installed. Lets set it up:

var partials = require('node-partials');
var templatePath = '/some/path/to/your/templates';

partials = new partials({
    delimiter: '## ',           // defaults to '## ' but can be pretty much whatever you want
    validFileTypes: ['html'],   // defaults to 'html' only
});

var templates = partials.compile(templatePath);
var serializedTemplates = partials.serializeTemplates(templates);

For node-partials to work, we create an instance that takes some options to know which type of files to look for and the delimiter to use for parsing the parials out of each of the template files. If you pass absolutely nothing, it will default to looking for .html files and use the double hash (##) as the partial name delimiter. Once it is initialized, we can call the .compile() function, passing a path to it. The module will traverse the directory looking for the types of files you specified, parse out the partials, run their contents through the Underscore/Lodash template function and store the compiled template in an object that is then returned.

When parsing the files, the name of the file/its path and the partial name will be used as the key to access the partial. For example, if a file with the name my-templates.html has the two partials in the example above, we would get two entries in the returned object that look like this:

{
    'my-template/some-page-component: <compiled template>,
    'my-template/text-content-partial: <compiled template>
}

Since the path/name of the file is used to construct the key, we can even have nested directories of templates. If we had some-widget/some-template.html, we would address the partials in like like this:

{
    'some-widget/some-template/<partial name>': <compiled template>
}

Rendering templates

Rendering the partials is nearly the same it was in my previous post. Rather than having a single variable, we have an object containing a bunch of templates. Putting it all together, it would look something like this:

var partials = require('node-partials');
var templatePath = '/some/path/to/your/templates';

partials = new partials({
    delimiter: '## ',           // defaults to '## ' but can be pretty much whatever you want
    validFileTypes: ['html'],   // defaults to 'html' only
});

var templates = partials.compile(templatePath);

console.log(templates['my-template/some-page-component']({ someData: 'some value' }));

Sharing the partials and templates with the client

Since each compiled template is a function, we can serialize everything and dump the source into a file that we can serve to the client, much like we did in the previous post. Once your templates are compiled, you can pass that object to the serialize() function of your instantiated node-partials object which will then return a stringified representation of the templates object that can then be passed to the client as a plain-old Javascript file.

var partials = require('node-partials');
var templatePath = '/some/path/to/your/templates';

partials = new partials({
    delimiter: '## ',           // defaults to '## ' but can be pretty much whatever you want
    validFileTypes: ['html'],   // defaults to 'html' only
});

var templates = partials.compile(templatePath);
var serializedTemplates = partials.serializeTemplates(templates);

When your templates are loaded on the client, the object can be found in the window.__views global variable and works exactly the as the templates object on the server.