grunt-hogan
a grunt task to precompile mustache templates with hogan.js
Getting Started
NOTE: This documentation is for grunt version 0.4+. To work with version 0.3.x, see here
Install this grunt plugin next to your project's Gruntfile.js with: npm install grunt-hogan --save-dev
Then add this line to your project's Gruntfile.js
:
grunt;
grunt-hogan
now uses standard grunt file directives for inputs and outputs.
To precompile a single src
template into a single dest
module:
grunt;
Multiple input templates via patterns
grunt;
Multiple input template patterns
//...mytarget : //... src : 'view/wwf/*.hogan' 'view/wcw/*.hogan' //...//...
Options
grunt-hogan
has been updated to support grunt's
task- and target-specific options.
In this way you can DRY out your template tasks.
Some previous "directives" have been deprecated in favor of the new option style. The old versions should still work (but will warn and explain what to change).
"Binders"
A single target can compile multiple hogan templates into a single file. The active "binder" is responsible for deciding how to join things together and what conventions/formats to use.
In general, most binders will result in a file containing a Javascript module, but this is customizable.
If a binder is not explicitly specified, the "default" binder will be used.
The "default" binder generates a javascript file
that is designed to work both as a node.js module and in the browser via a
<script/>
tag. Other built-in binders are:
- "hulk" - outputs results similar to hogan's "hulk" command line tool...which is "vanilla" javascript
- "nodejs" - exposes compiled templates as a node.js module
- "amd" - exposes compiled templates in amd format
- "revealing" - exposes compile templates via the revealing module pattern
You can also create your own binders. See the "Custom Binders" section below. If you think a binder is particularly useful and want it to become "built-in", feel free to send a pull request.
To specify a binder, use the "binderName" option:
//...mytarget : src : 'view/**/*.hogan' dest : 'hulkingup.js' options : binderName: 'hulk' //...
Custom Binders
Custom binders start life as a binder template that is compiled with the "bootstrap" binder into a node.js style javascript module.
grunt-hogan
simply expects to be able to require(...)
the module and access
a templates
attribute that is an associative array from [binderName]
to Hogan.Template
instance.
Creating Custom Binders
See the custombinder
and twocustombinders
targets in the
example custombinder gruntfile
for futher detail on creating and using custom binders.
Using Custom Binders
To use a custom binder, set the "binderPath" attribute to the desired javascript file:
//...options: binderPath : __dirname + '/my/custom/binders.js' binderName : 'mybinder'//...
If binderName
is unspecified, then the first binder in the module will be used (useful if you only have a single binder in your module):
//...options: binderPath : __dirname + '/my/custom/binders.js'//...
Using precompiled templates
As of version 0.2.2, all built in binders create javascript that functions similarly in intention, but varies with respect to the target use.
Given a precompile task like:
mytarget : src : 'view/fist.html' 'view/foe.html' 'view/what.you.gonna.do.html' dest : 'templates.js' options : binderName : 'nodejs'
A node.js application could:
//Load the modulevar templates = ; //Render a template with a context objectvar html1 = templates; //Render a template with context and partial templatesvar html2 = templates; //Render a template with a non-variable-like namevar html3 = templates'what.you.gonna.do'context:'catchphrase';
All of the binders (with the exceptions of special case binders like the bootstrap and "hulk") seek to expose the full api of the template render in this manner.
Also, if a partial parameter is not specified, the default render behavior is to make all the other templates in the binder ("sibling templates") available as partials in the render.
Other templates will vary slightly in their syntax to support their purpose.
Template naming
The default behavior of grunt-hogan
is to use the input templates file name (without the extension) as the name of the template in the output, precompiled result.
Thus an input of view/yada.hogan
will be available as templates.yada(...)
. However, there are plenty of scenarios where
one may want to customize this behavior. This is accomplished via the nameFunc
option on a task:
mytarget : src : './view/multi*.html' dest : './temp/namefunc.js' options : binderName: 'hulk' //Specify a custom name function { //Grab the path package here locally for clarity var _path = ; //'yada/yada/multi.1.js' -> 'multi.1' var name = _path ; //'multi.1' -> 'name_1' return 'name_'+name6; }
Partial Templates
Hogan supports Partial Templates as defined by the mustache spec.
Say we have a template (defined in a file named message.hogan
):
<p>Dear {{name}}, {{> mypartial}}</p>
And another template (defined in mypartial.hogan
):
<em>{{text}}</em>
Assuming you use a grunt-hogan
target to compile both these templates into a single module, you end up with a template render object something like:
message: {...} mypartial: {...}
We want Hogan to now expand the mypartial
template and interpret the message
template as:
<p>Dear {{name}}, <em>{{text}}</em></p>
But how do we give Hogan what it needs to resolve the mypartial
template? grunt-hogan
supports this through three features:
1. "Sibling" Partial Templates
By default, if you call the render function with just a context object:
template;
grunt-hogan
will make the mypartial
template available to the message
template automatically.
This will happen if:
message.hogan
andmypartial.hogan
were bound together into a single template render module- The
nameFunc
(if specified) preserves the partial namemypartial
mentioned in themessage.hogan
template
Since grunt-hogan
exposes the render as a function, this is the intended "common practice" for partial templates.
If you want a partial template to be automatically available, bind it as a sibling template with the template that depends on it.
2. Explicit Partial Templates
To disable the default behavior of "Sibling" Partial Templates, you simply specify the second parameter:
template;
But now you are on your own when resolving the Hogan.Template
objects passed through to the Hogan render. Hogan will use the passed partials only if they are valid Hogan.Template
instances.
exposeTemplates
task option
3. Use the If you don't know at template compile time what partials are needed,
and/or can't/won't put templates together as "Siblings", then you will need a way to retrieve the actual
Hogan.Template
instances from grunt-hogan
modules.
To do this, specify the exposeTemplates
option on the compile task.
Doing so makes the actual templates available as a template
property on the module:
message: {...} mypartial: {...} templates: message: ... mypartial: ...
Using this, you can pass the actual Hogan.Template
instance to wherever it is needed (with the "Explicit Partial Templates" mentioned above, for example).
Examples
Contributing
In lieu of a formal styleguide, take care to maintain the existing coding style. Add unit tests for any new or changed functionality. Lint and test your code using grunt.
Release History
- 0.3.1 - Updated the way grunt is specified in the
peerDependencies
- 0.3.0 - Improved grunt support
- Switched to lodash
- Upgraded hogan.js version
- Added CI build and testings
- Improved examples, and CI makes sure they work
- 0.2.2 - Binder template overhaul
- Added partial support on render functions
- Sibling partials by default
- Breaking changes for precompiled template API
- 0.2.1 - AMD Binder
- Now supports use of "sibling templates" (defined within the same binder) as partials
- Breaking change - Now exports a render function instead of the full template
- 0.1.1 - Breaking Changes and Custom Binder Support
- "render" directive has been discarded
- "options" notation has been discarded (supply attributes directly as keys on the target)
Acknowledgements
- a comment by "baz" here pointed me in the right direction
License
Copyright (c) 2014 Elliott B. Edwards
Licensed under the MIT license.