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 asbody.print(...args)— append to output.- All keys from
helpersanddataare available directly (via a scopedwith).
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 relativeinclude())views(string|string[]; lookup roots forinclude())ext(default.htmlfor include/layout resolution)cache(boolean; enable onrenderFile/ 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:
- Absolute path (with
extappended if missing). - Relative to current
filename(the template being rendered). - Inside
viewsdirectories (first match wins). - 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:
renderFilecaches compiled functions whenoptions.cache = true. - Layouts: only the last
layout()call wins; the page HTML is passed asbody. - Security: prefer
<%= %>; use<%- %>only for trusted content. - Whitespace: use
-%>to trim a single following newline. - Scope: template code runs inside a
withblock that mergeshelpersanddata.