#if(x) {# compiles to if (x) {. There is no second language to learn, no directives to memorise and no template dialect that behaves almost like JavaScript.
The same template renders the first response on a server and every update in the browser. One implementation, not two that have to be kept in step with each other.
A template compiles once into an ordinary function, which the engine then optimises like any other. No virtual DOM, no diffing pass, no build step.
<div id="app">
<h1>#title#</h1>
<ul>
#for(let item of items) {#
<li>#item#</li>
#}#
</ul>
</div>
<script>
const data = {
title: 'Reading list',
items: ['Dune', 'Solaris', 'Ubik']
};
const view = new hashJS("app");
view.bind(data);
</script> const hashJS = require('./hashJS.js');
// Compile once at startup.
const list = hashJS.compile(`
<h1>#title#</h1>
<ul>
#for(let item of items) {#
<li>#htmlEncode(item)#</li>
#}#
</ul>`);
// Render per request.
app.get('/books', async (req, res) => {
res.end(list({
title: 'Reading list',
items: await db.books.titles()
}));
}); Nothing about the template changes when it moves between the two. See it running →
Drop in one file. There is nothing to install and nothing to configure:
<script src="https://cdn.jsdelivr.net/gh/richdafunk/hashJS@v1.3.6/hashJS.js"></script>
The same file works under require on a server: it exports through module.exports as well as to the global scope.
A template is compiled and executed, so the template itself is code — treat it exactly as you would treat a .js file.
#htmlEncode(value)# so it lands as text rather than as markup. Compiling a template turns it into a function, which means new Function — and a strict policy blocks that unless it allows script-src 'unsafe-eval'.
You do not have to grant it. hashJS.precompile emits the render function as ordinary JavaScript source at build time; ship that file like any other script and hand it to hashJS.fromPrecompiled at runtime. Nothing is evaluated in the browser, so the policy stays closed.
// build step fs.writeFileSync('templates.js', 'window.T = { row: ' + hashJS.precompile(source) + ' };'); // in the page, under a policy with no unsafe-eval const row = hashJS.fromPrecompiled(window.T.row); list.innerHTML = users.map(row).join('');