αtαt
Fast and simple asynchronous JavaScript template engine without dependencies and for any environment (:
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 templatesparse
to parse a template, returns a render functionloadAndParse
the same with parse
but allows a path to a template as the first argumentrender
to parse and render a template, returns the result stringloadAndRender
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 helpersloader
templates provider
import { parse, render, config, DEFAULT_LOADER } from 'atat';
const options = {
it: "it",
$: "$",
helpers: { },
loader: DEFAULT_LOADER
};
config(options);
const tmpl = await parse(templateString, options);
const html = await render(templateString, { }, 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
moduleFETCH_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'),
{ },
{ loader: DEFAULT_LOADER },
);
const html = await loadAndRender(
'http://localhost:3000/views/main.html',
{ },
{ loader: FETCH_LOADER },
);
config({
loader: async (path) => {
const template = await loadTemplate(path);
return template;
}
});
Syntax
Encoded output
<p>@(it.user.firstName)@</p>
<p>@encode(it.user.firstName)@</p>
Raw html output
<p>@!(it.rawHTML)@</p>
Embedded JavaScript code
@{
// Any JavaScript code is acceptable in this block
const { firstName, secondName } = it.user;
}@
<p>@(firstName)@ @(secondName)@</p>
@if
@if (it.user != null) {
<p>@(it.user.firstName)@</p>
<p>@(it.user.secondName)@</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>
}@
@for
<ul>
@for(var i = 0, l = it.users.length; i < l; i++){
<li>@(it.users[i].firstName)@ @(it.users[i].secondName)@</li>
}@
</ul>
@while
<ul>
@{ var i = 0, j = 5; }@
@while (i < j) {
<li>@(i++)@</li>
}@
</ul>
Helpers
Custom helper
@<name>(<args...>)@
name
the valid nameargs...
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>
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 filemodel
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>
</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() {
});
</script>
}@
and another one to output the result anywhere
@section(<name>)@
index.atat
@layout('/views/_layout.atat')@
<div class="page-container">
Home page!
</div>
@section script {
<script>
document.addEventListener('DOMContentLoaded', function() {
});
</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() {
});
</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.