npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

htmlrl

v1.1.0

Published

A simple yet powerful HTML template utility library for Node.js

Readme

htmlrl (HTML Render Language)

htmlrl is a minimal, strict HTML template rendering engine for Node.js. It focuses on predictable output, automatic escaping, and a clear separation between logic and presentation.

Unlike template engines such as EJS or Pug, htmlrl does not embed JavaScript inside templates. Instead, it introduces a small, explicit render language designed to grow incrementally.

⚠️ Project status: Early-stage MVP.
The API and language are intentionally minimal and will expand over time.


Latest Update

Dual build support added: htmlrl now ships both ESM and CommonJS builds.

  • ESM users: continue using import Htmlrl from "htmlrl"
  • CommonJS users: use require("htmlrl").default to access the class

Features (MVP)

  • Simple variable replacement using @var
  • Automatic HTML escaping by default
  • Immutable render data
  • Fail-fast error handling
  • Deterministic rendering
  • Cache to avoid recompilation at every request
  • Full TypeScript support (works in both ESM and CommonJS projects)

Installation (via npm)

npm install htmlrl

To the npm site of htmlrl.


Example

Template (views/index.html)

<h1>@title</h1>
<p>Hello, @name!</p>

All html templates must be stored inside or in subdirectories of a central root directory which has to be specified in order to create a library instance.

TypeScript

// import library class
import Htmlrl from "htmlrl";

// create library instance
const htmlrl = new Htmlrl({
   // options
   rootDir: pathToViews // absolute path to the root directory which contains the templates
});

// render index.html
const generatedHtml = await htmlrl.renderAsync("index.html", {
    title: "Welcome to my page!",
    name: "John"
});

To use the library, you first have to create an instance and pass the mandatory options like rootDir. To render files use the asynchronous function renderAsync and pass the filename as a first, and the variables as a second argument.

Output

The above example evaluates to the following html string:

<h1>Welcome to my page!</h1>
<p>Hello, John!</p>

All variables are HTML-escaped automatically.

Precompilation

renderAsync automatically compiles your files at the first call and stores them in a cache for later usage and to avoid costly recompilation. If you want deterministic performance, especially with larger template files, it is recommended to use compileAsync to precompile the needed templates bevor they are actually used.

Example:

Write this in a suiting place in your source code. It should happen during the initialization phase of your app to avoid overhead later on.

await htmlrl.compileAsync("index.html");

And then again:

// uses the precompiled cache data
const generatedHtml = await htmlrl.renderAsync("index.html", {
    title: "Welcome to my page!",
    name: "John"
});

But this time there is no compiler overhead as it was already compiled bevor.


Security Notice

htmlrl performs basic HTML escaping only and is NOT context-aware.

This means:

  • Variable output is escaped for HTML text nodes only.
  • The engine does not detect whether a variable is rendered inside:
    • HTML attributes
    • URLs
    • JavaScript contexts
    • CSS contexts

Potentially Unsafe Usage

Example:

<a href="@url">Click</a>
<img src="@src">
<div onclick="@handler"></div>

Escaping alone is not sufficient in these contexts and may lead to security vulnerabilities such as XSS.

Your Responsibility

When using htmlrl, you must ensure that:

  • All data rendered into attributes or URLs is explicitly validated
  • Untrusted input is never rendered into executable contexts
  • You understand the HTML context where a variable is inserted

htmlrl intentionally avoids implicit complex, context-aware escaping to remain simple, predictable, and explicit.

Future versions may introduce optional mechanisms for safer attribute handling, but no automatic guarantees are currently provided.


Planned Features

  • Conditionals
  • Loops
  • Template partials
  • Improved diagnostics

This roadmap reflects intent, not guarantees.


License

This project is licensed under the MIT License.