html_render

The html_render module is a lightweight server-side template engine. It compiles templates with EJS‑style tags, supports includes, layouts, helpers, and safe HTML escaping.


Template Syntax

  • Code: <% code %> — runs JS/Bnlang code; no output.
  • Escaped output: <%= expr %> — evaluates and escapes HTML (& < > " ').
  • Raw output: <%- expr %> — evaluates without escaping (use with care).
  • Comment: <%# comment %> — ignored.
  • Trim next newline: close as -%> to remove one following newline.

Helpers & built‑ins inside templates

  • include(name, locals) — render another template and insert its HTML.
  • layout(name) — request a layout; the current template’s HTML is available as body.
  • print(...args) — append to output.
  • All keys from helpers and data are available directly (via a scoped with).

API Surface

compile(template: string, options?): (data, runtime?) => string

Compiles a template string into a render function.
Options:

  • openTag/closeTag (default '<%' / '%>')
  • helpers (object merged into scope)
  • escape (custom HTML escape function)
  • filename (absolute path; enables relative include())
  • views (string|string[]; lookup roots for include())
  • ext (default .html for include/layout resolution)
  • cache (boolean; enable on renderFile / adapter)

render(template: string, data?, options?): string

One‑shot render from a template string. Applies layout if invoked inside the template.

renderFile(filename: string, data?, options?, cb?)

Render a file. If cb provided, uses callback style; otherwise returns string or throws. Respects cache and views.

__bnl_html_render(filename, data, cb)

Express‑style adapter suitable for app.engine('html', __bnl_html_render). It reads data.settings.views, view options, and view cache to configure resolution and caching automatically.


File Resolution Rules

When include("name") or layout("name") is called, the engine resolves a file in this order:

  1. Absolute path (with ext appended if missing).
  2. Relative to current filename (the template being rendered).
  3. Inside views directories (first match wins).
  4. Relative to process.cwd().

If not found, it throws VIEW_NOT_FOUND with a list of tried paths.


Escaping

By default, <%= %> uses a tiny HTML escaper to encode & < > " '. Use <%- %> for raw HTML when you are sure the content is safe.


Examples (English only)

const { compile, render, renderFile } = require("html_render");

// 1) Render from string
const tpl = `
<h1>Hello, <%= user %></h1>
<% if (items && items.length) { %>
  <ul>
    <% for (const x of items) { %>
      <li><%= x %></li>
    <% } %>
  </ul>
<% } else { %>
  <p>No items</p>
<% } %>
`;

console.log(render(tpl, { user: "Mamun", items: ["a","b"] }));

// 2) Include & Layout (files)
/*
views/
  layouts/main.html
  partials/item.html
  home.html
*/

// home.html
/*
<% layout('layouts/main') %>
<h2>Welcome <%= user %></h2>
<ul>
  <% for (const x of items) { %>
    <%- include('partials/item', { x }) %>
  <% } %>
</ul>
*/

// layouts/main.html
/*
<!doctype html>
<html>
  <body>
    <header><h1>Site</h1></header>
    <main><%- body %></main>
  </body>
</html>
*/

// partials/item.html
/*
<li><%= x %></li>
*/

const html = renderFile("views/home.html", { user: "Mamun", items: ["a","b","c"] }, {
  views: "views",
  cache: true
});
console.log(html);

// 3) Custom helpers
const page = render("<p><%= upper('bnlang') %></p>", {}, {
  helpers: { upper: (s) => String(s).toUpperCase() }
});
console.log(page);

Notes

  • Caching: renderFile caches compiled functions when options.cache = true.
  • Layouts: only the last layout() call wins; the page HTML is passed as body.
  • Security: prefer <%= %>; use <%- %> only for trusted content.
  • Whitespace: use -%> to trim a single following newline.
  • Scope: template code runs inside a with block that merges helpers and data.