Razor Leaf is an HTML template engine for Node.js.
Features
-
automatic escaping
-
template inheritance
-
recursive macros
-
conditional attributes and classes
-
no extraneous rendered whitespace
-
no dependencies*
-
unrestricted JavaScript expressions and inline code; no sandboxes to work around
* This might change.
Example
example.rl
:
doctype html
head
meta charset: "utf-8"
meta name: "viewport" content: "initial-scale=1"
title "Example"
body
h1 "Hello, world!"
% const { left, right } = data;
p "#{left} × #{right} = #{left * right}"
example.js
:
const DirectoryLoader = ; const templateLoader = __dirname;const template = templateLoader; console;
Output:
Hello, world!
9 × 12 = 108
Syntax
Elements
Elements are defined by their names only; no other special character is necessary.
p
Void elements are recognized automatically.
meta
Strings
Strings are double-quoted and escaped for use in HTML as needed. Backslash escape codes can be used as in JavaScript. No whitespace is added around strings.
"--> A string <--\n" "A string containing \"double-quotes\""
--> A string <--A string containing "double-quotes"
Strings can also contain interpolated sections, delimited by #{
and }
.
#{
can be escaped with a leading backslash; }
doesn’t require escaping.
"#{6 * 7}"
42
If an exclamation mark precedes the string, it and any of its interpolated sections will not be escaped.
!"<!-- A significant comment -->"
<!-- A significant comment -->
Attributes
Attributes are marked up using the syntax name:
.
An attribute name can, optionally, be followed by a string to be used as
its value; if a value isn’t provided, the attribute is assumed to be boolean
(and present). Note that a string used as an attribute’s value cannot be “raw”
— that is, cannot be preceded by an exclamation mark.
meta charset: "utf-8"
Classes
Classes are marked up with a leading period, as in .class
.
fieldset .upload-meta
input.required
Hierarchy
Hierarchy in Razor Leaf is defined using indentation. For example:
doctype
html
head
meta charset: "utf-8"
title "Example"
link
rel: "stylesheet"
type: "text/css"
href: "stylesheets/example.css"
body
p id: "introduction"
"This template is a brief example of hierarchy."
ExampleThis template is a brief example of hierarchy.
Content found after an element on the same line will also be considered that element’s content.
Comments
Comments begin with #
and continue to the end of the line. They do not affect
the rendered HTML.
Code
Line code begins with %
and continues to the end of the line. Line code may
contain content (strings, elements, other code blocks, and special blocks, but
not attributes); if it does, the content is treated as a block and wrapped in
curly braces.
For example, this template:
% function countTo(n)
% for (var i = 1; i <= n; i++)
"#{i}"
% countTo(5);
might compile to this JavaScript:
{ for var i = 1; i <= n; i++ output += i; } ;
Block code begins with do
and treats all of its content as JavaScript.
do
const compareKeys = (a, b) =>
a.key < b.key ? -1 :
a.key > b.key ? 1 :
0;
const sorted = (array, by) =>
array
.map(value => ({key: by(value), value}))
.sort(compareKeys)
.map(({value}) => value);
for post in sorted(posts, post => post.title)
post-detail(post)
Special blocks
Some names define special blocks. These are:
doctype
: Inserts<!DOCTYPE html>
.if (condition)
: Includes its content only ifcondition
is met.elif (condition)
: Can immediately follow anif
or anelif
.else
: Can immediately follow anif
or anelif
.for (identifier) of (collection)
: Includes its content for each element of the array or array-like objectcollection
.for (identifier), (index) of (collection)
: Allows the index variable in afor
loop to be named.include (name)
: Loads and includes another template.extends (name)
: Loads another template and replaces its blocks. A template that extends another template cannot have any content outside of block actions.block (name)
: Defines a replaceable block.replace (name)
: Replaces a block.append (name)
: Appends to a block.do
: See Code.
API
new razorleaf.DirectoryLoader(root, [options])
Creates a loader that maps template names to files with the .rl
extension
in the directory located at root
.
razorleaf.DirectoryLoader.prototype.load(name, [options])
Returns a template object loaded from the root directory.
razorleaf.compile(template, [options])
Compiles a template string into a function. The compiled function takes
one argument, data
, which can be used (under that name) in the template.
Options
-
debug
: Iftrue
, warnings will be printed. (In a later version, this will enable error rewriting.) -
load(name)
: A function that returns a parsed template represented byname
. This is filled automatically by most loaders. -
globals
: An object representing the global variables that should be made available to the template.