I'm experimenting with HTML String template literals (Electron which uses NodeJS).
It works well but it looks like a mess. What I miss is the separation between HTML and logic.
module.exports = {
snippet: (value1, value2) => {
return `
<div>
<h1>Hello ${value1 + ' - ' + value2}</h1>
</div>
`;
},
};
What I wish I could do is like below (which does not work):
module.exports = {
snippet: (value1, value2) => {
return require('snippet.html')(value1, value2);
},
};
<div>
<h1>Hello ${value1 + ' - ' + value2}</h1>
</div>
I could get the HTML from the HTML file as a String. The problem is that it will be "flat" and I can't use the logic inside the template literals anymore.
I've read it's possible to run HTML as a String through eval
to make it work again. I've also read that it's not good for security and that it's slow.
module.exports
in the js file.I've now split logic from the template. Still, both are in the same file which makes the html less readable.
module.exports = {
snippet: (value1, value2) => {
/* Possible to put whatever logic in here */
return html(value1, value2);
},
};
function html(value1, value2) {
return `
<div>
<h1>Hello ${value1 + ' - ' + value2}</h1>
</div>
`;
}
In that case, the template literal is passed to your tag function, where you can then perform whatever operations you want on the different parts of the template literal. To escape a backtick in a template literal, put a backslash ( \ ) before the backtick. Dollar signs can be escaped as well to prevent interpolation.
When you use regular template literals, your input is passed to a default function that concatenates it into a single string. An interesting thing is that you can change it by preceding the template literal with your function name that acts as a tag.
With template literals, an expression can be embedded in a placeholder. A placeholder is represented by ${} , with anything within the curly brackets treated as JavaScript and anything outside the brackets treated as a string: const method = 'interpolation' const dynamicString = `This string is using ${method}.
The export declaration is used to export values from a JavaScript module. Exported values can then be imported into other programs with the import declaration or dynamic import.
I'm aware of Vue, React and other frameworks. I want to keep it small and without the hassle to setup a server this time.
Developing your own template framework is in no way a hassle free task. I don't know what do you mean by other frameworks
, but as you put this phrase along with monsters like Vue and React, I must guess that you do not know about small and simple template libraries. I'm not sure about current state of affairs, but last time I checked libraries like ones from this list or this list were quite small and simple to use
Or maybe you'll find this approach compelling https://jonsuh.com/blog/javascript-templating-without-a-library/
You don't really have to use module.exports
on latest NodeJS versions
If you OK with your Update
but the only issue is that template is in the same file as snippet, then what stops you from splitting files?
// app.js
console.log(require('./snippet.js').snippet(1,2))
// snippet.js
module.exports = {
snippet: (value1, value2) => {
/* Possible to put whatever logic in here */
return require('./template.js')(value1, value2)
},
}
// template.js
module.exports = (value1, value2) => `
<div>
<h1>Hello ${value1 + ' - ' + value2}</h1>
</div>
`
As a side note:
Eval is evil and slow
From MDN:
eval()
is a dangerous function, which executes the code it's passed with the privileges of the caller. If you runeval()
with a string that could be affected by a malicious party, you may end up running malicious code on the user's machine with the permissions of your webpage / extension.
So if you only run your own code through eval()
it is perfectly save... But, of course, as you implementing templates, that probably means that at some point you would want to allow user's input to the template, and that would call for troubles. So probably, yes, eval
is unsafe in your case.
I just wanted to point out that eval
is extremely dangerous, but not an absolute evil in all situation.
And it not necessary slow, either. When you say slow you must always ask yourself: "Compared to what? And in which situation?". Read the article and you will see why it can be slow. But can doesn't mean must.
From the same paragraph:
More importantly, a third-party code can see the scope in which eval() was invoked, which can lead to possible attacks in ways to which the similar Function is not susceptible.
You may consider using Function
. It is still dangerous. But less so.
On the second thougth - you should use Function
, or just drop the idea of writing your template engine altogether. Because it's insecurity doesn't matter: the idea to use template literals is as insecure as Function
is:
const template = (value1, value2) => `
<div>
<h1>Hello ${value1 + ' - ' + value2}</h1>
</div>
`
some_node.innerHTML = template("</h1><script>console.log("malicious injection")</script><h1>", "something else")
And by the way innerHTML
is also insecure
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