Liquid.js tutorial
last modified October 18, 2023
In this article we show how to use Liquid template engine in JavaScript applications.
Liquid
Liquid is a JavaScript template engine. It was created by Shopify.
Liquid files have the extension of .liquid
; they are a mix of
static data such as HTML and Liquid constructs.
Liquid uses the double curly brace delimiters {{ }}
for output
and the curly brace percentage delimiters {% %}
for logic.
{% if user != null %} Hello {{ user.name }} {% endif %}
This code is a sample Liquid syntax.
Template engine
A template engine or template processor is a library designed to combine templates with a data model to produce documents. Template engines are often used to generate large amounts of emails, in source code preprocessing, or producing dynamic HTML pages.
We create a template engine, where we define static parts and dynamic parts. The dynamic parts are later replaced with data. The rendering function later combines the templates with data.
Setting up Liquid.js
First, we install Liquid.js.
$ npm init -y
We initiate a new Node application.
$ npm i liquidjs
We install liquidjs
module with nmp i liquidjs
.
Liquid rendering from string
We start with a very simple example that renders from a string.
const Liquid = require('liquidjs'); const engine = new Liquid(); engine .parseAndRender('{{name | capitalize}}', {name: 'lucy'}) .then(console.log);
The example shows output from a string template. It also uses a filter.
const Liquid = require('liquidjs'); const engine = new Liquid();
We load the Liquid.js
module and initiate the engine.
engine .parseAndRender('{{name | capitalize}}', {name: 'lucy'}) .then(console.log);
The parseAndRender
function takes a template string and the context
data. Inside the template string, we have a name variable, which is passed to
the capitalize
filter. Filters modify the data before output.
$ node simple.js Lucy
Liquid sort filter
The sort
is one of the array filters available.
const Liquid = require('liquidjs'); const engine = new Liquid(); nums = [5, 3, 2, 4, 1] ctx = { data: nums} engine .parseAndRender('Sorted data: {{ data | sort }}', ctx) .then(console.log);
The example sorts data passed to the template string.
$ node sort_filter.js Sorted data: [1,2,3,4,5]
Liquid render from file
To render output from files, we use the renderFile
function.
$ mkdir views
We create a directory where we put our template files.
const Liquid = require('liquidjs'); const path = require('path'); const engine = new Liquid({ root: path.resolve(__dirname, 'views/'), extname: '.liquid' }); engine .renderFile('hello', { name: 'Peter' }) .then(console.log)
The example generates output from a text file.
const engine = new Liquid({ root: path.resolve(__dirname, 'views/'), extname: '.liquid' });
In the Liquid
constructor, we provide the template directory
location and the extension name. The extension name is usually
.liquid
.
engine .renderFile('hello', { name: 'Peter' }) .then(console.log)
The first parameter of the renderFile
is the template name. The
second parameter is context data.
Hello {{ name }}!
In the template file, we use {{}}
to output the context variable.
$ node from_file.js Hello Peter!
Liquid for tag
Liquid for
is an iteration tag which repeatedly executes a block of
code.
const Liquid = require('liquidjs'); const path = require('path'); const engine = new Liquid({ root: path.resolve(__dirname, 'views/'), extname: '.liquid' }); ctx = { users: [{ name: "Peter", age: 24 }, { name: "Lucy", age: 34 }] }; engine .renderFile("users", ctx) .then(console.log);
In the example, we define an array of users. The array is looped over in the
template with for
.
There are {{ users | size }} users {% for user in users -%} {{ user.name }} is {{ user.age }} years old {% endfor -%}
The template file outputs the number of users utilizing the size
filter and all the users from the context variable.
{% for user in users -%} {{ user.name }} is {{ user.age }} years old {% endfor -%}
We loop over the users array and print the attributs. Whitespace output can be controlled with dash characters.
$ node users.js There are 2 users Peter is 24 years old Lucy is 34 years old
Liquid partials
Partials are reusable templates that are included into other templates. Partials are used for duplicated content such as footers or headers.
Partials are inserted with include
directive.
const Liquid = require('liquidjs'); const path = require('path'); const engine = new Liquid({ root: path.resolve(__dirname, 'views/'), extname: '.liquid' }); ctx = { name: 'Peter' }; engine .renderFile("home", ctx) .then(console.log);
This example shows output from home.liquid
template, which includes
a Liquid partial.
{{ "now" | date: "%Y-%m-%d %H:%M" }}, ZetCode 2007 - 2022
This is a partial for a footer. With the help of the date
filter,
it shows current date and time.
Hello {{ name }}! {% include 'footer' %}
The footer
partial is included with include
directive.
$ node partials.js Hello Peter! 2019-02-13 22:52, ZetCode 2007 - 2022
Liquid inheritance
Liquid supports template inheritance. Template inheritance is a powerful feature that reduces code duplication and improves code organization. We define a base template from which we inherit in other template files. These template files overwrite specific blocks of the base template file.
const Liquid = require('liquidjs'); const path = require('path'); const engine = new Liquid({ root: path.resolve(__dirname, 'views/'), extname: '.liquid' }); engine .renderFile("derived", { content: 'Some content' }) .then(console.log)
The example generates output from a derived.liquid
template, which
uses inheritance techniquie.
Header {% block content %}My default content{% endblock %} Footer
This is the base.liquid
file from which other templates inherit.
The block/endblock
directives are used to declare a block of
content which is replaced in the child template.
{% layout "base" %} {% block content %} {{ content }} {% endblock %}
This is the child template. With the layout
directive, we inherit
from the base.liquid
template. We define the content with the
block/endblock
directives.
$ node inheritance.js Header Some content Footer
Liquid Express example
In the following example, we use Liquid in an Express application.
$ npm i express
We install the Express web framework.
const express = require("express"); const path = require("path"); const Liquid = require('liquidjs'); const engine = new Liquid(); const app = express(); app.engine('liquid', engine.express()); app.set('views', path.resolve(__dirname, "views")); app.set('view engine', 'liquid'); app.get("/today", (req, res) => { let today = new Date(); res.render("show_date", {now: today}); }); app.use((req, res) => { res.statusCode = 404; res.end("404 - page not found"); }); app.listen(3000, () => { console.log("Application started on port 3000"); })
The example is a simple web application created with Express. It shows the current date.
app.engine('liquid', engine.express()); app.set('views', path.resolve(__dirname, "views")); app.set('view engine', 'liquid');
We integrate Liquid into the Express application.
app.get("/today", (req, res) => { let today = new Date(); res.render("show_date", {now: today}); });
For the /today
path, we show current date. The
show_date.liquid
generates the ouput. We pass the now
context variable to the template.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Show date</title> </head> <body> <p> Today is {{ now }} </p> </body> </html>
The show_date.liquid
generates HTML output. It adds the current
date to the content with {{}}
.
$ node express-demo.js Application started on port 3000
We start the application.
$ curl localhost:3000/today <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Show date</title> </head> <body> <p> Today is Wed Feb 13 2019 23:19:07 GMT+0100 (Central European Standard Time) </p> </body> </html>
We create a request to the application with the curl
tool.
Source
In this article we have used Liquid.js to generate documents from Liquid templates and data. We covered Liquid tags, filters, partials, and inheritance.