Reputation: 387
thanks for any feedback...
I have an HTML template with JS string literals embedded...
<html>
<head>
<title>${title}</title>
</head>
<body>
User name: ${user.name}
</body>
</html>
I'm then doing...
let temp = require('./template.html')
return temp; // <--- I need this to return the compiled html
How can I get the string literals to render?
Is it even possible to do this?
I need the 'temp' variable to return as a compiled string so that I can insert it to a document.write later on in the code.
Thanks.
Upvotes: 1
Views: 768
Reputation:
You can create a new Function to turn it into a string template
return new Function("title","user","return `" + temp + "`;")(title,user);
As pointed out by T.J you will need to know all the variables used in the template and include them as arguments to the function.
Upvotes: 0
Reputation: 1074148
Those aren't string literals. They look like tokens in JavaScript's template literals.
Is it even possible to do this?
If you mean that you want to load the HTML dynamically and then use it as a template literal, you only have two choices for doing that:
Use a templating library (or write your own templating code) that parses the string and handles those tokens
Use eval
/ new Function
eval
(or new Function
) is not evil when used with your own content (and performance costs have been vastly overstated), though I'm not saying I'd recommend it. But this is how you'd do it (assuming that in your stack, require('./template.html')
will give you a string with the contents):
let temp = require('./template.html');
const template = "`" + temp.replace(/`/g, "\\`") + "`";
(There may be more escaping you want to do there, I just handled backticks.)
Then when you have the relevant tokens in scope:
const str = eval(template);
Live Example:
let temp = document.getElementById("template").textContent.trim();
const template = "`" + temp.replace(/`/g, "\\`") + "`";
// Using it
const title = "This is the title";
const user = {name: "Joe Blogs"};
const str = eval(template);
console.log(str);
<script type="text/template" id="template">
<html>
<head>
<title>${title}</title>
</head>
<body>
User name: ${user.name}
</body>
</html>
</script>
Why eval
instead of new Function
above? So that the code wrapping up the template for use doesn't have to know the names title
and user
. new Function
still allows arbitrary code execution, just like eval
, so you still can't use it except on your own content...
Upvotes: 1
Reputation: 257
Yes, it is possible with some minor modification to your code.
First rename template.html
to template.js
and change its content to
exports default ({title, user}) =>`
<html>
<head>
<title>${title}</title>
</head>
<body>
User name: ${user.name}
</body>
</html>`
Then let temp = require('./template.js')
will assign a function to temp that you should call with your context. Something like
let ctx = { title: 'titre', user: { name: 'alice' } }
let compiled = temp(ctx) // your compiled template
Check out yo-yo a library that works around this concept
Upvotes: 0