Overview

Bite.js is an ultra light-weight, full-featured templating engine designed for size and performance. It compiles templates into standalone functions in vanilla JavaScript that can be used to render those templates with a given set of data.

Features

  • Interpolation
  • Conditionals
  • Iteration
  • Parent/Child Scoping
  • Arbitrary Expressions
  • Precompilation or Run-Time Compilation
  • Partials

Installation

npm install bite-templates

Usage

Here is a simple example of how to compile and render a template.

const render = Bite('Hello, {{$.name}}!'); const result = render({name : 'Sam'}); console.log(result); // Hello, Sam!

By default, rendering a template with data returns a string. Passing true as the second parameter to the render function will return a DocumentFragment. This allows you to perform more complicated work on the DOM nodes such as adding event listeners.

const render = Bite('Hello, {{$.name}}!'); const result = render({name : 'Sam'}, true); console.log(result); // [object DocumentFragment] document.body.appendChild(result);

Now that we know how to compile and render templates, let's look at a more complicated example:

const template = ` {{#if ($.num1 + $.num2) % 2}} The sum is <b>odd</b>. {{#else}} The sum is <b>even</b>. {{/if}} `; const render = Bite(template); const result = render({num1 : 10, num2 : 4}); console.log(result); // The sum is <b>even</b>.

Here we demonstrate that arbitrary expressions can be evaluated within templates. Additionally, these expressions can be used within conditionals to determine what gets displayed.

Bite.js offers quite a few powerful features that allow you to control what gets rendered. Check out the Template API for a full list of features. You can also view and edit the live demo.

Scopes

Within a template, the current context, or scope, is always accessible via the $ variable. For instance, if your data looks like {name : 'Sam'}, your template can access that variable with $.name and can perform actions on it such as interpolation.

Within {{#with <expression>}} blocks, the scope is changed to the result of the expression passed to it. Similarly, within {{#forEach <array>}} blocks, the scope is changed to the current item in the array. In these cases, you can access the parent scope with $$. For example, to output a property from the parent scope you use {{$$.example}}. You can climb further up the parent scope chain via $$.$$, $$.$$.$$, and so on. For example: {{$$.$$.example}}

Partials

Partials are templates included inside of other templates. This functionality is implemented inherently via HTML Interpolation. HTML Interpolation supports both raw HTML and DOM nodes, so you can use both the string and DocumentFragment forms of the partial's render function.

Partials can be more easily explained via example:

const render = Bite('Hello, {{$.name}}! {{% $.reverse_partial({first_name : $.name})}}'); const partial = Bite('Your name reversed is: {{$.first_name.reverse()}}!'); const result = render({ name : 'Sam', reverse_partial : partial, }); console.log(result); // Hello, Sam! Your name reversed is: maS!

Pre-Compilation

Templates can be pre-compiled into functions on the server within your Node.js application. Calling toString() on a compiled template function will return a string which can then be saved however you wish (file, database, etc). These strings can be sent straight to the client as either a standalone JavaScript file or as part of other source files depending on your build workflow.

If you're using Webpack, you can use the bite-templates-loader package to automatically precompile your templates before sending them to the client.

Template API

Interpolation

{{<expression>}}
Interpolation allows you to inject arbitrary values and expressions into your template. The most common use-case is outputting a property such as a name or date, e.g. {{$.name}}. However, any valid JavaScript expression is allowed, such as {{1 + 2 + 3}}, {{'Mr. ' + $.last_name}}, or {{$.name.toUpperCase()}}.
Note: Interpolated values are HTML-escaped to avoid injection attacks. If you need to inject HTML without escaping, see HTML Interpolation.

HTML Interpolation

{{% <expression>}}
HTML Interpolation allows you to inject arbitrary values and expressions into your template without HTML-escaping them. This can also be used to inject DOM nodes instead of HTML strings (see the partials section for more information).
Caution: HTML Interpolating untrusted strings and DOM nodes can lead to potential injection attacks. Use wisely!

If

{{#if <expression>}} ... {{#elseif <expression>}} ... {{#else}} ... {{/if}}
The if block allows you to control the flow of your code by testing certain conditions. Within the block, {{#elseif <expression>}} and {{#else}} blocks can optionally be used. Any valid JavaScript expression can be used with #if and #elseif.

Repeat

{{#repeat <number>}} ... {{/repeat}}
The repeat block allows you to repeat a subsection of the template a given number of times. Within the block, i becomes the current iteration counter. #repeat behaves like a standard for loop, starting with 0 and counting up to, but not including, the target number.

ForEach

{{#forEach <array>}} ... {{/forEach}}
The forEach block allows you to loop over an array of values and output a subsection of the template. The result of the expression passed to #forEach must be an array. Within the block, i becomes the current index in the array, $ becomes the current value, and $$ becomes the parent scope. You can climb further up the parent scope chain via $$.$$, $$.$$.$$, and so on.

With

{{#with <expression>}} ... {{/with}}
The with block allows you to change the current scope within the template. $ becomes the value of the expression passed to the block, and $$ becomes the parent scope. You can climb further up the parent scope chain via $$.$$, $$.$$.$$, and so on.

Demo

Here is a live, editable demo showing use of all the features Bite.js has to offer. Feel free to experiment.

Template
JavaScript
Output
Compiled Function