Vento
This is a minimal template engine inspired by other great engines like Nunjucks, Liquid, Mustache, and EJS.
Why another template engine?
Because I couldn't find the "perfect" template engine for me (probably this one neither is). The issues I found in existing template engines:
Nunjucks
(It's my favorite template engine so far).
- I like:
- I can invoke functions like
{{ user.getName() }}
. - Very flexible, with many built-in filters and features
- I can invoke functions like
- I don't like:
- It's not well maintained. The last version was released in Jun 2022. And the previous version in 2020.
- It's not async-friendly. For example, you have some tags to work with sync
values (like
for
andif
) and others for async values (likeasyncEach
andifAysnc
). Some features don't work in async contexts. - To me, it's very uncomfortable to have to type the delimiters
{%
and%}
all the time (especially the%
character). - By default, all variables are escaped, so you have to remember to use the
safe
filter everywhere. This is not very convenient for my use case (static site generators), where I can control all the content and the HTML generated. - Some filters are too specific.
Liquid
I like:
- The support for async evaluation is less hacky than Nunjucks.
- The variables are not escaped by default, there's an
escape
filter for that.
I don't like:
- It's not possible to invoke functions in a liquid template. For example
{{ user.getName() }}
fails. - It has the same problem as Nunjucks with the
%
character in the delimiters.
- It's not possible to invoke functions in a liquid template. For example
EJS/Eta
- I like:
- It allows running any javascript code in the template.
- I don't like:
- It has the same problem with the
%
character. And I don't like the opening and closing delimiters (<%
and%>
). - Because it runs javascript, it's very verbose to do a simple
forEach
orif
.
- It has the same problem with the
Mustache
- I like:
- Very simple, everything is inside
{{
and}}
. - The closing tag is
{{/tagname}}
, very nice!
- Very simple, everything is inside
- I don't like:
- Perhaps too simple and the syntax can be a bit confusing.
- Partials. It's not easy to include them dynamically.
- The data context is a bit confusing to me.
- Very uncomfortable to work with filters.
What this new template engine has to offer?
First, let's take a look at this syntax example:
{{ if printName }}
{{ await user.getName("full") |> toUpperCase }}
{{ /if }}
- Everything is between
{{
and}}
tags. Unlike Nunjucks or Liquid, there's no distinction between tags{% tag %}
and printing variables{{ var }}
. - The closed tag is done by prepending the
/
character (like Mustache). - Async friendly.
- Like EJS, you can use real JavaScript code everywhere.
await user.getName("full")
is real JS code that will be executed at runtime. - Filters are applied using the
pipeline operator
(
|>
). Note: this is not exactly like the last proposal for JavaScript, it's inspired by (the previous proposal that was rejected but it's way more simple and fits better for filters. - Filters can run prototype methods. In this example
users.getName("full")
returns a string, so thetoUpperCase
is a method of theString
object. It's the same asusers.getName("full").toUpperCase()
.
Getting started
See Getting started on the docs.
Editor support
See Editor integrations on the docs.