Flora - Streaming templates for Node.js

tdlr; check out flora, a templating engine that allows you to stream HTML.

A greatly under-appreciated feature of HTML is that it can be streamed. The browser can begin parsing and displaying part of the page while the rest is still being downloaded.

However most server-side frameworks and template engines assume that creating HTML is done synchronously. This means if you need to do anything slow, like make a database request, your users won't start seeing content until all of that is done. This is a travesty!

Think about this; you display the user's name on the page and you need to make a database request to get the name. While you are making that request you could be sending this HTML:

<!doctype html>
<html lang="en">
<head>
  <title>My app!</title>
  <link href="/styles/site.css">
  <script src="/scripts/app.js" async></script>
<body>
  <nav class="navbar"> ... </nav>
  <header> ... </header>

All of the above HTML does not depend on the database request. This means that, while the request is in flight your user could be:

Node.js' support for streaming is awesome. The response object in a request is a writable stream. You can write data to it incrementally.

However Node's ecosystem support for streaming HTML is, frankly, terrible. Now we see the major frameworks competing to see who can have the best async/await approach. But async is the wrong model for web servers. Web server should never block rendering of HTML. Only block when you absolutely have to. I'll save this rant for a future article.

Enter flora

flora is a library I've been working on that allows you to stream HTML. It allows you to provide promises and streams as data to the template. This allows it to flush out any HTML that is not waiting on these promises and streams, making sure your HTML is as fast possible. It looks like this:

const {html} = require('flora-tmpl');

function template({name}) {
  return html`
    <!doctype html>
    <html lang="en">
    <title>My app!</title>
    <link href="/styles/site.css">
    <script src="/scripts/app.js" async></script>

    <nav class="navbar"> ... </nav>
    <header> ... </header>
    <div class="user">${name}</div>
  `;
}

async function getUserName() {
  let user = await db.getUser();
  return user.name;
}

require('http').createServer(function(request, response){
  let name = getUserName();

  template({ name }).pipe(response);
}).listen(8080);

What is happening here is:

Native JavaScript templates

I spent quite a bit of time going back-and-forth deciding on a templating syntax for flora before I realized that I didn't need to create one; JavaScript has templates baked in through tagged template functions. This was quite a revelation for me!

Instead of learning a new template language you can just use normal JavaScript template interpolation.

Flora includes a special map function which takes a stream and a callback, allowing you to produce HTML for each item that comes through the stream. It looks like this:

const {html, map} = require('flora-tmpl');

function template({stream}) {
  return html`
    <!doctype html>
    <html lang="en">
    <title>Todo list</title>
    <main>
      <h1>Todo list</h1>
      <ul>
        ${map(stream, item => (
          html`
            <li>${item}</li>
          `
        ))}
      </ul>
    </main>
  `;
}

template({stream: getTodos()}).pipe(process.stdout);

Producing this:

Streaming HTML

Please check out flora and tell me what you think. And next time you write a back-end the same old blocking way, know that there is a better way, with streams!