Basic functionality

<ul>
  for (var i = 0; i != 5; i++) {
    <li data-index="${ i }">Item ${ i + 1 }</li>
  }
</ul>
<ul>
    <li data-index="0">Item 1</li>
    <li data-index="1">Item 2</li>
    <li data-index="2">Item 3</li>
    <li data-index="3">Item 4</li>
    <li data-index="4">Item 5</li>
</ul>

Templates are compiled down to valid JavaScript. Markup is usually echoed as a template literal which allows you to output expressions while in the markup context.

// child.nhp
// ---------
// <p>${ input.name.toUpperCase() }</p>
// exports.value = 42;

var a = 5;

var child = await include('./modules/child.nhp', {
  name: 'John'
});

<h1>Value: ${ child.value }</h1>
<p>JOHN</p>
<h1>Value: 42</h1>

You can pass arguments to included templates. Those templates, on the other hand, can export data—just like a Node module!

// data.json
// ---------
// {
//   "text": "This is JSON!"
// }

var ms = require('ms');
var data = require('./modules/data.json');

<h1>${ ms(Math.random() * 10e4) }</h1>
<pre>${ data.text }</pre>
<h1>1m</h1>
<pre>This is JSON!</pre>

The Node.js require() function works the same way in templates as it does in modules. In this case, it loads the ms utility and a local file.

var content = capture(() => {
  <div>
    <p>Hello!</p>
  </div>
});

<div>
  echo(content.toUpperCase());
</div>

exports.markup = content;
<div>
  <DIV>
    <P>HELLO!</P>
  </DIV>
</div>

You can capture markup in a variable by using the special capture() function. Then, you can export that markup for usage elsewhere.

<echo plain>
  with the "plain" option, you can echo stuff like:
  ` ' " \ \n \r ${ not a template literal }
</echo>

<echo escape>
  "escape" simply escapes
  <strong>all tags</strong>
  and other "HTML entities"
</echo>

<echo strip>
  <span>
    <p>
      "strip" removes whitespace between tags
    </p>
  </span>
</echo>

  with the "plain" option, you can echo stuff like:
  ` ' " \ \n \r ${ not a template literal }

  &quot;escape&quot; simply escapes
  &lt;strong&gt;all tags&lt;/strong&gt;
  and other &quot;HTML entities&quot;
<span><p>
      "strip" removes whitespace between tags
    </p></span>

To export larger chunks of markup, you can use the special <echo> tags that are used solely by the compiler. You can also specify options that alter the output.

Asynchronicity ✨

var promises = [];

for (var i = 0; i != 5; i++) {
  let wait = Math.random() * 250;

  promises.push(new Promise((resolve, reject) => {
    setTimeout(() => {
      <h1>Waited ${ wait }ms!</h1>
      resolve();
    }, wait);
  }));
}

<p>About to wait for stuff...</p>
await Promise.all(promises);
<p>Stuff happened, continue.</p>
<p>About to wait for stuff...</p>
      <h1>Waited 16.805723364723857ms!</h1>
      <h1>Waited 61.814942530506514ms!</h1>
      <h1>Waited 97.37256353720863ms!</h1>
      <h1>Waited 186.47862845252777ms!</h1>
      <h1>Waited 204.97742907579024ms!</h1>
<p>Stuff happened, continue.</p>

Templates are compiled down to an async function. This means you can use await to resolve the template only after a certain asynchronous action (a Promise) has resolved first.

var axios = require('axios');
var endpoint = 'https://baconipsum.com/api/?type=all-meat&paras=1';

await axios({
  method: 'get',
  url: endpoint,
  timeout: 2000
}).then((res) => {
  res.data.forEach((para) => {
    <p>${ para }</p>
  });
}).catch((err) => {
  <p>Could not load bacon. 🐷</p>
});
    <p>Biltong tri-tip shankle, swine capicola picanha ham hock meatloaf t-bone kevin fatback.  Tongue beef turducken meatloaf, shoulder tail shankle biltong ball tip prosciutto chicken corned beef.  Bacon picanha capicola boudin meatloaf burgdoggen.  Ribeye doner pork belly short loin tri-tip shank.  Doner sirloin tri-tip ham hock kevin cow ribeye t-bone leberkas prosciutto.  Kevin bacon strip steak frankfurter corned beef swine tenderloin sirloin.  Landjaeger chicken venison shankle, andouille bresaola ball tip doner drumstick bacon.</p>

You can easily fetch data from an external source. In this case, we use the axios module to quickly load some bacon ipsum.


Note: These demos are run when you load the page and the output you've seen above is the actual output they've produced. See for yourself.