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

atat

v1.2.12

Published

Fast and simple template engine

Downloads

26

Readme

αtαt

Fast and simple asynchronous JavaScript template engine without dependencies and for any environment (:

Build Status

But why?

I wanted to create something simple for what you don't need to spend hours to read the documentation, something that you can start to use in a few minutes. The main idea is using pure JavaScript with pure HTML. You don't need to learn new syntax, just do everything like in JavaScript.

Features

  • Embedded JavaScript code
  • Browser support
  • Complies with Express
  • Layouts, partials and sections
  • No dependencies and very small size
  • TypeScript support
  • Easy to use

Installation

Using yarn or npm:

$ yarn add atat
$ npm install --save atat

Tests

Using yarn or npm:

$ yarn test
$ npm test

Usage

import { config, parse, loadAndRender, render, loadAndParse } from 'atat';

var atat = require('atat');

atat object has the following methods

  • config to setup global configuration for all templates
  • parse to parse a template, returns a render function
  • loadAndParse the same with parse but allows a path to a template as the first argument
  • render to parse and render a template, returns the result string
  • loadAndRender the same with render but allows a path to a template as the first argument
import { parse, loadAndRender, render, loadAndParse } from 'atat';

const render = await parse(templateString, options);
container.innerHTML = render(model);

container.innerHTML = await render(templateString, model, options);

const render = await loadAndParse(pathToTemplate, options);
container.innerHTML = render(model);

container.innerHTML = await loadAndRender(pathToTemplate, model, options);

If your environment doesn't support async/await sytax, use Promise

render(templateString, options).then((err, result) => {
  container.innerHTML = result;
});

Options

  • it models variable name, default "it"
  • $ helpers variable name, default "$"
  • helpers extra helpers
  • loader templates provider
import { parse, render, config, DEFAULT_LOADER } from 'atat';
const options = {
    it: "it",
    $: "$",
    helpers: { },
    loader: DEFAULT_LOADER
};

// global config will be applied to all templates
config(options);

// also you can pass options to the parse and render methods
const tmpl = await parse(templateString, options);
const html = await render(templateString, { /* model */ }, options);

Loaders

Loaders allow you to load templates asynchronously. There are two default loaders available right from the library:

  • DEFAULT_LOADER - for Node.js, default loader, uses fs module
  • FETCH_LOADER - for a browser, loads templates through fetch method
import { loadAndRender, loadAndParse, config, FETCH_LOADER, DEFAULT_LOADER } from 'atat';

const html = await loadAndRender(
  path.resolve(__dirname, './views/main.html'),
  { /* model */ },
  { loader: DEFAULT_LOADER },
);

// in a browser you must specify loader, at least FETCH_LOADER
const html = await loadAndRender(
  'http://localhost:3000/views/main.html',
  { /* model */ },
  { loader: FETCH_LOADER },
);

// custom loader
config({
  loader: async (path) => {
    const template = await loadTemplate(path);
    return template;
  }
});

Syntax

Encoded output

<p>@(it.user.firstName)@</p>

<!-- 
  Model: { user: { firstName: 'Charlotte' } }
  Output:
  <p>Charlotte</p>
 -->

Raw html output

<p>@!(it.rawHTML)@</p>

<!-- 
  Model: { rawHTML: '<i>Hello!</i>' }
  Output:
  <p><i>Hello!</i></p>
 -->

Embedded JavaScript code

@{
  // Any JavaScript code is acceptable in this block
  var firstName = it.user.firstName;
  var secondName = it.user.secondName;
}@

<p>@(firstName)@ @(secondName)@</p>

<!-- 
  Model: { user: { firstName: 'Charlotte', secondName: 'Gamboa' } }
  Output:
  <p>Charlotte Gamboa</p>
 -->

@if

@if (it.user != null) {
<p>@(it.user.firstName)@</p>
<p>@(it.user.secondName)@</p>
}@

<!-- 
  Model: { user: { firstName: 'Charlotte', secondName: 'Gamboa' } }
  Output:
  <p>Charlotte</p>
  <p>Smith</p>
 -->

@if...else if...else

@if(it.user && it.user.firstName && it.user.secondName){
<p>@(it.user.firstName)@</p>
<p>@(it.user.secondName)@</p>
} else if (it.user && it.user.firstName) {
<p>@(it.user.firstName)@</p>
} else {
<p>User is not defined</p>
}@

<!-- 
  Model: { user: { firstName: 'Charlotte', secondName: '' } }
  Output:
  <p>Charlotte</p>
 -->

@for

<ul>
  @for(var i = 0, l = it.users.length; i < l; i++){
  <li>@(it.users[i].firstName)@ @(it.users[i].secondName)@</li>
  }@
</ul>

<!-- 
  Model: { users: [{ firstName: 'Charlotte', secondName: 'Gamboa' }] }
  Output:
  <ul>
    <li>Charlotte Gamboa</li>
  </ul>
 -->

@while

<ul>
  @{ var i = 0, j = 5; }@
  @while (i < j) {
  <li>@(i++)@</li>
  }@
</ul>

<!-- 
  Output:
  <ul>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
  </ul>
 -->

Helpers

Custom helper

@<name>(<args...>)@

  • name the valid name
  • args... whatever you want
const options = {
    $: '$',
    helpers: {
      l10n: (lang, key) => resources[lang][key];
    }
};

const result = await atat.render(template, { lang: 'en' }, options);
<title>@l10n(it.lang, "title")@</title>
<title>@('My Website - ' + $.l10n(it.lang, "title"))@</title>

<!-- 
  Model: { lang: 'en' }
  Output:
  <title>Main page</title>
  <title>My Website - Main page</title>
 -->

Default helpers

  • @json(<object>)@ returns a result of JSON stringify
  • @encode(<string>)@ the same as @(<string>)@
  • @join(<array>, <separator>)@ joins the array with the separator (optional)
  • @upper(<string>)@ simple uppercase
  • @lower(<string>)@ simple lowercase

Layout

@layout(<path>)@

  • path the path to the layout file

index.atat

@layout('/views/_layout.atat')@
<div class="page-container">
  Home page!
</div>

/views/_layout.atat

<html>
  <head></head>
  <body>
    <main>
      @!(body)@
    </main>
  </body>
</html>

Output:

<html>
  <head></head>
  <body>
    <main>
      <div class="page-container">
        Home page!
      </div>
    </main>
  </body>
</html>

Patrial

Patrials allow you to reuse useful pieces of code in different places

@partial(<path>, <model>)@

  • path path to partial a view file
  • model model for a partial view (optional)

views/_menu.atat

<nav role="main">
  <ul>
    <li>
      <a href="/" class="@(it.page=='home'?'active':'')@">Home</a>
    </li>
    <li>
      <a href="/about" class="@(it.page=='home'?'active':'')@">About</a>
    </li>
  </ul>
</nav>

views/_layout.atat

@{ const { $route } = it; }@
<html>
  <head></head>
  <body>
    @partial('/views/_menu.atat', $route)@
    <main>
      @!(body)@
    </main>
  </body>
</html>

Output:

<html>
  <head></head>
  <body>
    <nav role="main">
      <ul>
        <li>
          <a href="/" class="active">Home</a>
        </li>
        <li>
          <a href="/about" class="">About</a>
        </li>
      </ul>
    </nav>
    <main>
      <!-- Home page content -->
    </main>
  </body>
</html>

Section

Section allows you to pass HTML markup from a view to a layout level

Use the following syntax to specify a new section

@section script {
<script>
  document.addEventListener('DOMContentLoaded', function() {
    // your code is here
  });
</script>
}@

and another one to output the result anywhere

@section(<name>)@

  • name sections name

index.atat

@layout('/views/_layout.atat')@
<div class="page-container">
  Home page!
</div>
@section script {
<script>
  document.addEventListener('DOMContentLoaded', function() {
    // your code is here
  });
</script>
}@

/views/_layout.atat

<html>
  <head></head>
  <body>
    <main>
      @!(body)@
    </main>
    @section('script')@
  </body>
</html>

Output:

<html>
  <head></head>
  <body>
    <main>
      <div class="page-container">
        Home page!
      </div>
    </main>
    <script>
      document.addEventListener('DOMContentLoaded', function() {
        // your code is here
      });
    </script>
  </body>
</html>

ExpressJS Integration

Just set 'view engine' value to atat

const express = require('express');

const app = express();

app.set('views', './views');
app.set('view engine', 'atat');

Example available here

Demo

Live demo

License

The JavaScript Templates script is released under the MIT license.