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

node-tao

v0.0.5

Published

Lightweight, fast, and powerful embedded JS template engine

Downloads

11

Readme

Node Tao

TAO is a simple, lightweight and very fast embedded JS templating. It emphasizes great performance, security, and developer experience.

🌟 Features

  • 🚀 Super Fast
  • 🔧 Configurable
  • 🔥 Caching
  • ⚡️ Support for partials
  • 📝 Easy template syntax (no prefix needed)
  • 💻 Developer experience
  • 🧩 Support for local and global helpers
  • 🛡️ Security by design
  • 🟦 Official VS Code Extension

Get Started

Define a template simple.html inside a view directory templates

<!-- templates/simple.html -->
<h1>Hi <%= name %>!</h1>
import { Tao } from 'tao';

const tao = new Tao({ views: path.join(__dirname, 'templates') });

const res = tao.render('simple', { name: 'Tao' });
console.log(res); // <h1>Hi Tao!</h1>

Helpers

Helpers are functions that can be used inside a template. Helpers can be local (only available in a particular render) or global (available everywhere on the instance).

import { Tao } from 'tao';

const tao = new Tao({ views: path.join(__dirname, 'templates') });

// Global helper
function nPlusTwo(n: number) {
  return n + 2;
}
// Global helper need to be registered on the instance
tao.defineHelpers({ nPlusTwo });

// Render a template
app.get('/', (req, res) => {
  // Local helper
  function nPlusOne(n: number) {
    return n + 1;
  }

  const res = tao.render('simple', { name: 'Ben' }, { nPlusOne });
  console.log(res); // <h1>Hi Ben!</h1>
});

Usage:

// simple.html
<%= nPlusOne(1) %>

NB: Always escape (=) the output of a helper function when it includes user-controlled data.

It is also possible to register helpers on globalThis without providing them to the template engine, but it can lead to name collision.

Include

In your template, you might want to include other templates:

<h1>Hi <%= name %>!</h1>
<!-- include "article" template and provide data -->
<%~ include('article', { phone: 'Tao T9' }) %>

Child components will inherit from data and helpers provided in the parent component.

Template prefix options

There are three differents template prefixes:

<!-- Evaluation (''): no escape (ideal for js execution) -->
<% const age = 33; %>
<!-- Interpolation (=): escaping (ideal for data interpolation) -->
<p><%= `Age: ${age}` %></p>
<!-- Raw (~): no escape (ideal for HTML inclusion) -->
<%~ include('product') %>

NB: Those prefix are configurable in the options.

Template paths resolution

TAO will recursively add all templates matching the containing views path definition

import { Tao } from 'tao';

const tao = new Tao({ views: path.join(__dirname, 'templates') });

...such that following structure is ok :

| /templates
|   - simple.html         ✔️
|   /products
|     - article.html      ✔️
|     /...
|       - nested.html     ✔️

By default, fileResolution is set to flexible, which means that you can just provide the unique end of the path:

const res = tao.render('nested'); // accepted ✔️
const res = tao.render('products/.../nested'); // not necessary ❌

TAO will successfully identify the nested templates without providing the subfolder(s).

Programmatically defined templates

You might want to define programmatically templates:

const headerPartial = `
  <header>
    <h1><%= title %></h1>
  </header>
`;

tao.loadTemplate('@header', headerPartial);
const rendered = tao.render('@header', { title: 'Computer shop' });

Cache Storage

TAO uses cache stores to manage caching. You might want to interact with those stores to retrieve or delete an entry:

tao.helpersStore.remove('myHelperFn');

Providing optionnal data into the template

If you wish to provide optional data to the template, prefix your data with tao:

// template.html
<p><%= tao.error?.firstName %></p>

tao is an object containing all the provided data and is always defined. This is particularly useful when providing optional validation error data (data that you don’t always pass into the template).

Security by design

By default, TAO assume you are running your app in production, so no error will be thrown, such that error stack traces are not visible in your browser. Errors will be displayed in your editor console, and visual error representation (see developer experience) is available in your browser by setting debug: true at option initialisation.

🟦 Official VS Code Extension

VS Code Marketplace

Developer experience

All methods, properties are correctly typed and documented, so you should get help from your editor.

In case of an error, a visual representation is available in your browser, giving you all the details and the precise line of the error (if available).

Error representation

NB: set debug: true to activate this option. Do not activate this option in production.

Metrics are also available, so you get usefull informations about the template rendering time, cache hit, mapped templates, etc. in your browser console.

Metrics

If you want to inspect the data provided to the template, it is available directly in your browser console under the object data.

Data

NB: set metrics: true to activate this option. Do not activate this option in production.

Integration with Web Framework

Fastify:

import { Tao } from 'node-tao';
import Fastify from 'fastify';
const fastify = Fastify();

const tao = new Tao({ views: 'src', development: true });

declare module 'fastify' {
  interface FastifyReply {
    html(payload: string): FastifyReply;
  }
}

fastify.decorateReply('html', function (payload: string) {
  return this.type('text/html').send(payload);
});

fastify.get('/tao', (request, reply) => {
  const result = tao.render('test', { name: 'Fastify' });
  return reply.html(result);
});

try {
  await fastify.listen({ port: 3000 });
} catch (err) {
  fastify.log.error(err);
  process.exit(1);
}

Express:

import express from 'express';
import { Tao } from 'node-tao';
export const app = express();
app.use(express.json());

const tao = new Tao({ views: 'src', development: true });

app.get('/tao', (req, res) => {
  const result = tao.render('test', { name: 'Express' });
  res.send(result);
});

app.listen(3000, () => {
  console.log('listening on *:3000');
});

FAQs

It started as a fork of eta, but became a dedicated library because the changes made were too significant. Some parts are still based on eta, especially the template parsing, and if you know eta, the API will be familiar.

  • Tao set security by design: Stack traces are not visible in the browser. Increased security in files mapping.
  • Increased developer experience: Visual error representation, metrics, configuration options are checked.
  • Immutability: Data provided in the template is immutable, ie. template data modification does not affect original data.
  • Clearer API: Scope is well defined and restricted, which also improves security. Clean code practices are enforced.
  • Clearer template syntax: No prefix are needed.
  • Helpers: Global and local helpers, which are clearer and more suitable for little template logic.
  • Flexible template path resolution: With fileResolution mode set to flexible, only end unique paths can be provided, which increases file path readability (aka. namespaces).
  • Vscode extension: Official vscode extension.
  • Performance: Various performance optimization.
  • Testing: Modern and up to date numerous tests.
  • No async support: Supporting async rendering (e.g., await include) within templates encourages placing too much logic in the view layer and can be considered as an anti-pattern. Templates should be responsible for displaying data, while controllers should handle logic. Async behavior in templates would also require error handling (e.g., try/catch), adding complexity and possible errors. Async logic in template make it impossible de optimize through a Promise.all or any parallelism, hard to test and debug. In short: if you have async data, fetch it beforehand and render it synchronously.

  • No layouts: Layouts are essentially includes and add unnecessary complexity to the rendering process.

  • No rmWhitespace: Stripping whitespace at the template level yields negligible HTML size savings. Using compression (e.g., via Nginx or other proxies) is far more effective and scalable.

If you think those features are absolutely necessary, please open a new discussion on github and provide an example.

Change logs

V0.0.2: Fix node modules exclusion in files matching for the error template.

V0.0.3: Data exchange for the official extension, and various improvements.

V0.0.4: Fix NaN or Infinity value provided inside an object into the template.

V0.0.5: Fix character escape triggering an invalid js syntax.

Credits

  • Syntax and some parts of compilation are based on eta.