Render twig templates
This plugin requires Grunt ~0.4.5
If you haven't used Grunt before, be sure to check out the Getting Started guide, as it explains how to create a Gruntfile as well as install and use Grunt plugins. Once you're familiar with that process, you may install this plugin with this command:
npm install grunt-twig-render --save-dev
Once the plugin has been installed, it may be enabled inside your Gruntfile with this line of JavaScript:
grunt.loadNpmTasks('grunt-twig-render');
In your project's Gruntfile, add a section named twigRender
to the data object passed into grunt.initConfig()
.
grunt.initConfig({
twigRender: {
options: {
// Task-specific options go here.
},
your_target: {
options: {
// Target specific options go here
},
files : [
{
data: // Path to JSON, JSON5 or YAML file, or POJO, or Array of filepaths and POJO
template: // Path to template file
dest: // Path to output destination here
}
]
},
},
});
You can also use Grunt built-in files syntax for more dynamic lists.
In that case, one of data
or template
must be specified, the other one will use the dynamic src
property.
Note: The files
parameter must be an array, and must conform to the format specified above. Each object in the file array represents one rendered template.
files: [
{
data: "path/to/data/file.json",
template: "path/to/template.twig",
dest: "file/to/output.html"
}
]
files: [
{
data: {
greeting: "Hello",
target: "world"
},
template: "path/to/template.twig",
dest: "file/to/output.html"
}
]
Compile all your templates, with data from a central data file:
grunt.initConfig({
twigRender: {
your_target: {
files : [
{
data: 'path/to/datafile.json',
expand: true,
cwd: 'path/to/templates/',
src: ['**/*.twig', '!**/_*.twig'], // Match twig templates but not partials
dest: 'path/to/output/',
ext: '.html' // index.twig + datafile.json => index.html
}
]
},
},
});
Compile a list of posts, same template but different data files:
grunt.initConfig({
twigRender: {
your_target: {
files : [
{
template: 'path/to/template.twig',
expand: true,
cwd: 'path/to/data/',
src: ['post*.json'], // post1.json, post2.json,...
dest: 'path/to/output/',
ext: '.html' // post1.json + template.twig => post1.html
}
]
},
},
});
The data
parameter accepts multiple formats, here is a detailed description of each.
JSON file should end in .json
, YAML in .yml
.
JSON5 is an extension to standard JSON, allowing (among other things) comments and multi-line strings. This is an optional format, to enable it you need to install JSON5:
npm install json5
Then simply set data
to the path of a json5 file (ending in .json
or .json5
).
Used as is.
Each element of the array can be any of the accepted format, results are merged. In case of conflicts, last data in the array has priority.
An optional dataPath
string can be supplied, in dot notation format.
If supplied, renderer will look for it in the loaded data and pass it as dataPath
property to the template.
This lets you call the same template with different parts of the data tree.
files: [
{
data: {
post: {
title: "a new post",
content: "about life"
info: {
published: "2014/09/12",
size: 1234,
author: "John Doe"
}
}
}
dataPath: "post.info",
},
Then in template post.twig
use {{dataPath.published}}
directly
If the data parameter results in an array
(either through dataPath or as file containing a Javascript array),
then multiple destination files are generated.
Their names are the destination
parameter with '_(number)' appended to the filename.
For example:
{
"posts": [
{
"title": "first post",
"content": "Lorem ipsum dolor sit amet, consectetur adipisicing elit."
},
{
"title": "another post",
"content": "Fugiat enim, at sit natus temporibus maxime repudiandae."
}
]
}
<h1>{{dataPath.title}}</h1>
<p>{{dataPath.content}}</p>
grunt.initConfig({
twigRender: {
your_target: {
files : [
{
data: "path/to/data/data.json",
dataPath: "posts",
template: "path/to/one_post.twig",
dest: "file/to/post.html"
}
]
},
},
});
post_0.html
post_1.html
If the data parameter results in a tree (that is, an array containing some arrays),
you can use the flatten
property to reduce this into a list:
#####data.json
{
"menu": [
{"label": "action1"},
{"label": "action2"},
{
"label": "sub-menu",
"actions": [
{"label": "action3"},
{"label": "action4"}
]
}
]
}
#####Gruntfile
files: [
{
data: "data.json",
dataPath: "menu",
flatten: "actions"
template: "myTemplate.twig",
dest: "myDest.html"
},
Will result in 4 files (myDest_0-3.html
)
Type: Boolean
Default value: false
Indicates if Twig should use a template cache or read template file every time. Default is set to false to enable template file watch and recompilation. Set it to true if you need to generate lots of files with an identical template.
Type: Array
Default value: []
Can be an array of functions that extend TwigJS.
options:
{
extensions:
[
// Usage: {{ [1, 2, 3]|fooJoin(' | ') }}
// Output: 1 | 2 | 3
function(Twig)
{
Twig.exports.extendFilter( "fooJoin", function(value, params)
{
if (value === undefined || value === null)
{
return;
}
var join_str = "",
output = [],
keyset = null;
if (params && params[0])
{
join_str = params[0];
}
if (value instanceof Array)
{
output = value;
}
else
{
keyset = value._keys || Object.keys(value);
Twig.forEach(keyset, function(key)
{
if (key === "_keys")
{
return; // Ignore the _keys property
}
if (value.hasOwnProperty(key))
{
output.push(value[key]);
}
});
}
return output.join(join_str);
});
}
]
}
options:
{
extensions:
[
// Usage:
// {% for i in 1..3 %}
// {{ fooCycle(['odd', 'even'], i) }}
// {% endfor %}
// Output:
// even
// odd
// even
function(Twig)
{
Twig.exports.extendFunction( "fooCycle", function(arr, i)
{
var pos = i % arr.length;
return arr[pos];
});
},
// load data dynamically from file
// Usage:
// data.json: { "test": "foobar" }
// {% set mydata = data("path/to/jsonOrYml/data.json") %}
// {{ mydata.test }}
// Output:
// foobar
function(Twig)
{
Twig.exports.extendFunction('data', function(filename)
{
var namespace_path = Twig.path.parsePath.apply(this, [this, filename]);
if (/\.yml$/i.test(namespace_path) || /\.yaml/i.test(namespace_path)){
return grunt.file.readYAML(namespace_path);
} else {
return grunt.file.readJSON(namespace_path);
}
});
}
]
}
options:
{
extensions:
[
// Usage:
// {% fooSpaceless %}<div>
// <b>b</b> <i>i</i>
// </div>{% endFooSpaceless %}
// Output:
// <div><b>b</b><i>i</i></div>
function(Twig)
{
Twig.exports.extendTag(
{
type: "fooSpaceless",
regex: /^fooSpaceless$/,
next: [
"endFooSpaceless"
],
open: true,
// Parse the html and return it without any spaces between tags
parse: function (token, context, chain)
{
// Parse the output without any filter
var unfiltered = Twig.parse.apply(this, [token.output, context]),
// A regular expression to find closing and opening tags with spaces between them
rBetweenTagSpaces = />\s+</g,
// Replace all space between closing and opening html tags
output = unfiltered.replace(rBetweenTagSpaces,'><').trim();
return {
chain: chain,
output: output
};
}
});
},
function(Twig)
{
Twig.exports.extendTag(
{
type: "endFooSpaceless",
regex: /^endFooSpaceless$/,
next: [ ],
open: false
});
}
]
}
options:
{
extensions:
[
function(Twig)
{
// Although it might not be obvious, you have access to the Twig instance within this function
// and can configure TwigJS as you like
// disables caching
Twig.cache = false;
}
]
}
Type: Object
Default value: {}
Object hash defining functions in TwigJS.
options {
functions: {
asset: function(arg) { return 'my-asset-location/' + arg; }
}
}
Type: Object
Default value: {}
Object hash defining filters in TwigJS.
options {
filters: {
dots: function(arg) { return arg + '...'; }
}
}
For a complete list of available params see the official twigjs documentation
1.8.3
- Improved error message output.
1.8.2
- Updated twig.js to 1.12.0.
1.8.1
- Updated twig.js to 1.10.4.
1.8.0
- Allows to use all available twigjs parameters and provides a more lightweight way to define custom functions and filters.
1.7.4
- Updated twig.js to 0.10.0.
1.7.3
- Updated twig.js to 0.8.8.
1.7.2
- Twig errors now cause grunt task to fail and logs the error.
1.7.1
- bugfix: array of data did not merge objects recursively, now does.
1.7.0
- added
cache
option to enable/disable Twig caching (needed for livereload).
1.6.0
- added
flatten
option to flatten data lists for multi-files generation.
1.5.0
- task renamed to
twigRender
(wastwig_render
), to comply with Javascript conventions and make jshint happy in client codes.
1.4.1
- dataPath returns full data object with additional
dataPath
property, instead of just the data pointed to (allows template to access full context).
1.4.0
- dataPath parameter, to load sub-part of a data structure.
- data arrays to generate multiple destinations.
1.3.0
- Use src for data or template, allowing globbing and more
- Allow use of JSON5, if library is present (optional).
1.2.0
- Allowing data to be an array of strings/objects.
1.1.0
- Added support for YAML data files.
1.0.1
- Added debug output when the target file has been written.
1.0.0
- Rechecked code. Seems to be fine – releasing version 1.0.0.
0.3.1
- Updated version string.
0.3.0
- Added option to extend TwigJS functionality (filters, functions, tags).
0.2.0
- Added basic tests.
0.1.0
- Defined twigRender task.