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
helpers
anddata
are 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.html
for 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
ext
appended if missing). - Relative to current
filename
(the template being rendered). - Inside
views
directories (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:
renderFile
caches 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
with
block that mergeshelpers
anddata
.