Is there a template engine that will parse templates in the style of ES6 template literals (e.g. "string ${var}"
) without violating a Content-Security-Policy (CSP) restriction on script evaluation?
The CSP restrictions on script evaluation prevent eval
, new Function
, setTimeout(string)
and setInterval(string)
.
There are a number of template engines that can provide or be modified to provide something like ES6-style template literals, such as John Resig's MicroTemplates, lodash _.template and DoT.js. However all seem to violate the CSP by using new Function
.
It would in some ways be convenient if var
could be unrestricted Javascript, but for apparent reasons this may not be possible. However I would need to be able to modify the engine to format the output as desired.
In the circumstances performance is not a concern, and pre-compiling the templates is not an option. Others have discussed pre-compilation.
As an additional restriction, the content is text - not HTML. I do not think DOM-oriented templating engines such as Knockout or PURE would not work effectively, as a result.
My first thought is to start with mustache.js and modify it from there (i.e. change mustache.tags = ['${', '}']
or a DIY solution, but I would be grateful for any thoughts on the topic in general as there seems to be quite a dearth of discussion on CSP and templates.
If all you need is key value substitution, you can make do with a simple function like the templateReplace that I provide below. No eval involved, only regular expressions.
If you need to include 'unrestriced javascript', have content like ${[1,2,3].join(', ')}
then, as you acknowledged, you will obviously need a solution that will violate your CSP policy.
var templateReplace = function(html, data, keyTemplate) {
if (!keyTemplate || typeof keyTemplate !== 'string' || keyTemplate.indexOf('key') === -1) {
keyTemplate = '{{key}}';
}
return (Object.keys(data) || []).reduce(function(html, key) {
var val = (data[key] !== undefined) ? data[key] : '';
return html.replace(new RegExp(keyTemplate.replace('key', key), 'gi'), val);
}, html);
};
// demo 1, using {{key}} syntax
(function() {
var li = [{ text: 'one' }, { text: 'two' }, { text: 'three' }].map(function(d) {
return templateReplace( '<li>Item: {{text}}</li>', d);
});
document.querySelector('#result1').innerHTML = li.join('\n')
}())
// demo 2, using ${key} syntax
(function() {
var helloWorld = templateReplace('${hello} ${world}', { hello: 'Hello', world: 'World!' }, '\\${key}');
document.querySelector('#result2').innerHTML = helloWorld;
}())
demo 1 - {{key}} syntax
<div id="result1"></div>
demo 2 - ${key} syntax
<div id="result2"></div>
Micromustache library does exactly that. version 6 supports setting custom open and close markers (${
and }
instead of {{
and }}
) which makes it more of a drop-in replacement for template literals.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With