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 🙏

© 2025 – Pkg Stats / Ryan Hefner

templora

v1.3.4

Published

A light weight template engine for nodejs express and fastify application

Readme

Templora

Overview

This is a lightweight js template engine for Node.js that supports:

  • <% %> JavaScript code blocks
  • {{ }} → Text and number output
  • {{{ }}} → Raw HTML output
  • include() → Partial templates
  • layout() → Layouts with nested templates
  • Global and per-render helpers
  • Template caching for performance

It is designed to be simple, flexible, and easy to integrate with Express and Fastify.


Include it in your project:

//ES5
const { renderFile, registerHelper } = require("templora");

//ES6
import { renderFile, registerHelper } from "templora";

Express Integration

const express = require("express");
const path = require("path");
const { renderFile, registerHelper } = require("templora");

const app = express();

// Register the engine
app.engine("html", renderFile);
app.set("views", path.join(__dirname, "views"));
app.set("view engine", "html");

// Register a global helper
registerHelper("upper", str => String(str).toUpperCase());

app.get("/", (req, res) => {
  const students = [
    { name: "Tom", age: 20 },
    { name: "Alice", age: 25 }
  ];

  res.render("index", {
    title: "Home Page",
    name: "World",
    students,
    layout: "main", // layout file without extension
    helpers: {
      greet: n => `Hello, ${n}!`
    }
  });
});

app.listen(4000, () =>
  console.log("Server running on http://localhost:4000")
);

Fastify intergration

const fastify = require("fastify")();
const path = require("path");
const pointOfView = require("point-of-view");
const { renderFile, registerHelper } = require("gate");

// Register a global helper
registerHelper("upper", str => String(str).toUpperCase());

// Register point-of-view with Gate
fastify.register(pointOfView, {
  engine: {
    html: renderFile, // Gate engine
  },
  root: path.join(__dirname, "views"), // template directory
  viewExt: "html",  // default extension
  options: {
    // any options passed to renderFile
  }
});

// Routes
fastify.get("/", async (request, reply) => {
  const students = [
    { name: "Tom", age: 20 },
    { name: "Alice", age: 25 }
  ];

  return reply.view("index", {
    title: "Home Page",
    name: "World",
    students,
    layout: "main", // layout path without extension
    helpers: {
      greet: n => `Hello, ${n}!`
    }
  });
});

// Start server
fastify.listen({ port: 4000 }, (err, address) => {
  if (err) throw err;
  console.log(`Server running at ${address}`);
});

Features

1. JavaScript Code Blocks

Use <% %> to run arbitrary JavaScript in your templates:

<% for (let i = 0; i < items.length; i++) { %>
  <li>{{ i }} - {{ items[i] }}</li>
<% } %>

<!--  -->

<% students.map(student => {%>
  {{student.name}}
  {{{ include("partials/user", {student}) }}} <!--acces students from the partial-->
<%})%>

Supports:

  • for, while, do…while
  • if, else if, else
  • forEach, map
  • Any valid JavaScript code

2. Variable Interpolation

Escaped Output

  • Syntax: {{ expression }}
  • Automatically escapes HTML to prevent XSS attacks.
<p>User Name: {{ user.name }}</p>

Raw Output

  • Syntax: {{{ expression }}}
  • Inserts raw HTML without escaping.
<p>HTML Content: {{{ user.htmlContent }}}</p>

3. Layouts

You can wrap your template in a layout:

  • Layout files can contain {{{ body }}} for inner template content.

Example layouts/main.html:

<!DOCTYPE html>
<html>
<head>
  <title>{{ title }}</title>
</head>
<body>
  {{{ body }}} OR {{{ main }}}
</body>
</html>

4. Includes (Partials)

Include partial templates:

{{{ include("partials/header",{name:'tom'}) }}}
  • Paths are relative to the current template.
  • Variables can be passed as an object.

5. Helpers

Global Helpers

You can register helpers once, and they are available in all templates:

registerHelper("upper", str => String(str).toUpperCase());
registerHelper("lower", str => String(str).toLowerCase());
registerHelper("repeat", (str, n) => String(str).repeat(n));

Usage in templates:

<p>{{ upper(user.name) }}</p>
<p>{{ lower(user.name) }}</p>
<p>{{ repeat("-", 10) }}</p>

Per-render Helpers

You can also pass helpers per render:

res.render("home", {
  data,
  helpers: {
    shout: s => s.toUpperCase() + "!!!"
  }
});
  • Per-render helpers override global helpers if names collide.

6. Template Caching

  • Compiled templates are cached in memory in production for faster rendering but not cached in development.
  • The engine automatically reuses compiled functions for repeated renders in production.

Example Template (views/home.html)


<h2>User Information</h2>
<p>Name (escaped): {{ user.name }}</p>
<p>Name (raw): {{ user.name }}</p>

<p>Uppercase (helper): {{ upper(user.name) }}</p>

<h3>Items List</h3>
<ul>
<% items.forEach((item, i) => { %>
  <li>{{ i }} - {{ item }} </li>

<% }) %>
</ul>
{{{ include("partials/footer",{item}) }}}

Notes & Best Practices

  1. HTML Escaping: Use {{ }} for user input to prevent XSS. Use raw versions only for trusted content.
  2. Helpers: Use global helpers for reusable functions. Per-render helpers are useful for one-off templates.
  3. Includes & Layouts: Paths are relative to the template file.
  4. Caching: Templates are cached automatically inproduction, not in development; both restarting the server and refreshing the page reloads them in developement.
  5. JS Blocks: Any valid JS code is allowed inside <% %> blocks. Use them for loops, conditionals, and variable manipulation.

Syntax Summary

| Feature | Syntax / Notes | | -------------------- | --------------------------------------------------------- | | Escaped variable | {{ var }} | | Raw HTML variable | {{{ var }}} | | JS blocks | <% JS code %> | | Layout placeholder | {{{ main }}} or {{{ main }}} | | Include partials | {{{ include('relative/path/to/partial', {data}) }}} | | Global helpers | registerHelper('name', fn) | | Per-render helpers | helpers option in res.render() | | Loops & conditionals | <% for(...) { %> ... <% } %> | | Caching | Enabled in production, auto-reload in dev | | Optional semicolons | Supported in <% %> blocks |