What is liquidjs?
LiquidJS is a JavaScript implementation of the Liquid templating language, which was originally created by Shopify. It allows you to render dynamic content in your web applications by using a simple and readable syntax. LiquidJS is highly extensible and can be used both on the server-side with Node.js and in the browser.
What are liquidjs's main functionalities?
Basic Template Rendering
This feature allows you to render basic templates with dynamic content. In this example, the template 'Hello, {{name}}!' is rendered with the variable 'name' set to 'World', resulting in 'Hello, World!'.
const { Liquid } = require('liquidjs');
const engine = new Liquid();
const template = 'Hello, {{name}}!';
engine.parseAndRender(template, { name: 'World' }).then(console.log);
Loops
This feature allows you to iterate over arrays and render each item. In this example, the template iterates over the 'items' array and renders each item, resulting in 'apple banana cherry '.
const { Liquid } = require('liquidjs');
const engine = new Liquid();
const template = '{% for item in items %}{{ item }} {% endfor %}';
engine.parseAndRender(template, { items: ['apple', 'banana', 'cherry'] }).then(console.log);
Conditionals
This feature allows you to use conditional statements in your templates. In this example, the template checks if the 'user' variable exists and renders 'Hello, Alice!' if it does, otherwise it renders 'Hello, Guest!'.
const { Liquid } = require('liquidjs');
const engine = new Liquid();
const template = '{% if user %}Hello, {{ user.name }}!{% else %}Hello, Guest!{% endif %}';
engine.parseAndRender(template, { user: { name: 'Alice' } }).then(console.log);
Filters
This feature allows you to use filters to transform output. In this example, the 'upcase' filter is used to convert the string 'hello' to uppercase, resulting in 'HELLO'.
const { Liquid } = require('liquidjs');
const engine = new Liquid();
const template = '{{ "hello" | upcase }}';
engine.parseAndRender(template).then(console.log);
Other packages similar to liquidjs
nunjucks
Nunjucks is a powerful templating engine for JavaScript, inspired by Jinja2. It offers a similar feature set to LiquidJS, including template inheritance, macros, and filters. Nunjucks is known for its flexibility and ease of use, making it a strong alternative to LiquidJS.
handlebars
Handlebars is a popular templating engine that provides a simple way to build semantic templates. It supports features like nested templates, partials, and helpers. Handlebars is known for its simplicity and performance, making it a good choice for projects that require straightforward templating.
ejs
EJS (Embedded JavaScript) is a templating engine that lets you generate HTML with plain JavaScript. It supports features like partials and includes, and is known for its simplicity and ease of integration with Express.js. EJS is a good option for developers who prefer a more JavaScript-centric approach to templating.
liquidjs
This is a liquid implementation for both Node.js and browsers. Website: http://harttle.github.io/liquidjs/, Live Demo: https://jsfiddle.net/6u40xbzs/
Features
- Fully compatible to shopify, with all tags and filters implemented
- Support layout(extend) and include syntax
- In pure JavaScript with any-promise as the only one dependency
Differences
Though being compatible with Ruby Liquid is one of our priorities, there're still certain differences. You may need some configuration to get it compatible in these senarios:
- Dynamic file locating (enabled by default), which means layout/partial name can be an variable in liquidjs. See #51.
- Truthy and Falsy. All values except
undefined
, null
, false
are truthy, whereas in Ruby Liquid all except nil
and false
are truthy. See #26. - Number Rendering. Since JavaScript do not distinguish
float
and integer
, we cannot either convert between them nor render regarding their type. See #59.
TOC
Render from String
Install as Node.js dependency:
npm install --save liquidjs
Parse and Render:
var Liquid = require('liquidjs');
var engine = Liquid();
engine
.parseAndRender('{{name | capitalize}}', {name: 'alice'})
.then(console.log);
Caching templates:
var tpl = engine.parse('{{name | capitalize}}');
engine
.render(tpl, {name: 'alice'})
.then(console.log);
Render from File
var engine = Liquid({
root: path.resolve(__dirname, 'views/'),
extname: '.liquid'
});
engine.renderFile("hello.liquid", {name: 'alice'})
.then(console.log)
engine
.renderFile("hello", {name: 'alice'})
.then(console.log)
Use with Express.js
app.engine('liquid', engine.express());
app.set('views', './views');
app.set('view engine', 'liquid');
Here's an Express demo. When used with Express.js,
Express views
will be included when looking up
partials(includes and layouts).
Use in Browser
You can get a dist file for browsers from
Here's the demo:
Note: For IE and Android UC browser, you will need a Promise polyfill.
Include Partials
// file: color.liquid
color: '{{ color }}' shape: '{{ shape }}'
// file: theme.liquid
{% assign shape = 'circle' %}
{% include 'color' %}
{% include 'color' with 'red' %}
{% include 'color', color: 'yellow', shape: 'square' %}
The output will be:
color: '' shape: 'circle'
color: 'red' shape: 'circle'
color: 'yellow' shape: 'square'
Layout Templates (Extends)
// file: default-layout.liquid
Header
{% block content %}My default content{% endblock %}
Footer
// file: page.liquid
{% layout "default-layout" %}
{% block content %}My page content{% endblock %}
The output of page.liquid
:
Header
My page content
Footer
- It's possible to define multiple blocks.
- block name is optional when there's only one block.
Options
The full list of options for Liquid()
is listed as following:
-
root
is a directory or an array of directories to resolve layouts and includes, as well as the filename passed in when calling .renderFile()
.
If an array, the files are looked up in the order they occur in the array.
Defaults to ["."]
-
extname
is used to lookup the template file when filepath doesn't include an extension name. Eg: setting to ".html"
will allow including file by basename. Defaults to ""
.
-
cache
indicates whether or not to cache resolved templates. Defaults to false
.
-
dynamicPartials
: if set, treat <filepath>
parameter in {%include filepath %}
, {%layout filepath%}
as a variable, otherwise as a literal value. Defaults to true
.
-
strict_filters
is used to enable strict filter existence. If set to false
, undefined filters will be rendered as empty string. Otherwise, undefined filters will cause an exception. Defaults to false
.
-
strict_variables
is used to enable strict variable derivation.
If set to false
, undefined variables will be rendered as empty string.
Otherwise, undefined variables will cause an exception. Defaults to false
.
-
trim_tag_right
is used to strip blank characters (including
, \t
, and \r
) from the right of tags ({% %}
) until \n
(inclusive). Defaults to false
.
-
trim_tag_left
is similiar to trim_tag_right
, whereas the \n
is exclusive. Defaults to false
. See Whitespace Control for details.
-
trim_value_right
is used to strip blank characters (including
, \t
, and \r
) from the right of values ({{ }}
) until \n
(inclusive). Defaults to false
.
-
trim_value_left
is similiar to trim_value_right
, whereas the \n
is exclusive. Defaults to false
. See Whitespace Control for details.
-
greedy
is used to specify whether trim_left
/trim_right
is greedy. When set to true
, all consecutive blank characters including \n
will be trimed regardless of line breaks. Defaults to true
.
Register Filters
engine.registerFilter('upper', v => v.toUpperCase())
Filter arguments will be passed to the registered filter function, for example:
engine.registerFilter('add', (initial, arg1, arg2) => initial + arg1 + arg2)
See existing filter implementations here: https://github.com/harttle/liquidjs/blob/master/filters.js
Register Tags
engine.registerTag('upper', {
parse: function(tagToken, remainTokens) {
this.str = tagToken.args;
},
render: function(scope, hash) {
var str = Liquid.evalValue(this.str, scope);
return Promise.resolve(str.toUpperCase());
}
});
parse
: Read tokens from remainTokens
until your end token.render
: Combine scope data with your parsed tokens into HTML string.
See existing tag implementations here: https://github.com/harttle/liquidjs/blob/master/tags/