Deploying to gh-pages from @ harttle/liquidjs@ed15a52c26 🚀

This commit is contained in:
harttle
2026-06-07 16:27:46 +00:00
parent 1f4d8787e0
commit e5d9012ccb
135 changed files with 1173 additions and 1021 deletions
+4 -3
View File
@@ -39,6 +39,7 @@
<script src="https://cdn.cookiehub.eu/c2/e8e44c93.js"></script>
<script type="text/javascript">
document.addEventListener("DOMContentLoaded", function(event) {
if (location.hostname === 'localhost' || location.hostname === '127.0.0.1') return;
var cpm = {};
window.cookiehub.load(cpm);
});
@@ -99,12 +100,12 @@
</header>
<div class="article-content" itemprop="articleBody">
<p>As covered in <a href="/tutorials/register-filters-tags.html">Register Filters/Tags</a>, we can access filter arguments directly in filter function like:</p>
<p>As covered in <a href="/tutorials/register-filters-tags.html">Register Filters/Tags</a>, we can access filter arguments directly in a filter function like:</p>
<pre class="line-numbers language-javascript" data-language="javascript"><code class="language-javascript"><span class="token comment">// Usage: &#123;&#123; 1 | add: 2, 3 &#125;&#125;</span>
<span class="token comment">// Output: 6</span>
engine<span class="token punctuation">.</span><span class="token function">registerFilter</span><span class="token punctuation">(</span><span class="token string">'add'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">initial<span class="token punctuation">,</span> arg1<span class="token punctuation">,</span> arg2</span><span class="token punctuation">)</span> <span class="token operator">=></span> initial <span class="token operator">+</span> arg1 <span class="token operator">+</span> arg2<span class="token punctuation">)</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span></span></code></pre>
<p>When it comes to stateful filters, for example transform a URL path to full URL, well need to access a <code>origin</code> in current scope:</p>
<p>When it comes to stateful filters, for example transforming a URL path to a full URL, well need to access an <code>origin</code> in the current scope:</p>
<pre class="line-numbers language-javascript" data-language="javascript"><code class="language-javascript"><span class="token comment">// Usage: &#123;&#123; '/index.html' | fullURL &#125;&#125;</span>
<span class="token comment">// Scope: &#123; origin: "https://liquidjs.com" &#125;</span>
<span class="token comment">// Output: https://liquidjs.com/index.html</span>
@@ -121,7 +122,7 @@ engine<span class="token punctuation">.</span><span class="token function">regis
</div>
<footer class="article-footer">
<time class="article-footer-updated" datetime="2026-06-06T17:38:08.030Z" itemprop="dateModified">Last updated: 2026-06-06</time>
<time class="article-footer-updated" datetime="2026-06-07T16:27:07.441Z" itemprop="dateModified">Last updated: 2026-06-07</time>
<a href="register-filters-tags.html" class="article-footer-prev" title="Register Filters/Tags"><i class="icon-chevron-left"></i><span>Prev</span></a><a href="parse-parameters.html" class="article-footer-next" title="Parse Parameters"><span>Next</span><i class="icon-chevron-right"></i></a>
</footer>
</div>
+4 -3
View File
@@ -39,6 +39,7 @@
<script src="https://cdn.cookiehub.eu/c2/e8e44c93.js"></script>
<script type="text/javascript">
document.addEventListener("DOMContentLoaded", function(event) {
if (location.hostname === 'localhost' || location.hostname === '127.0.0.1') return;
var cpm = {};
window.cookiehub.load(cpm);
});
@@ -99,9 +100,9 @@
</header>
<div class="article-content" itemprop="articleBody">
<p>In a typical website project, well have a directory of view templates and theyll be rendered multiple times. In production environment the template files are not likely to be changed over time (other than re-deployments). Thus it makes sense to cache the file contents and the parsed templates (in a kind of AST) to improve performance.</p>
<p>In a typical website project, well have a directory of view templates and theyll be rendered multiple times. In a production environment the template files are not likely to change over time (other than re-deployments). Thus it makes sense to cache the file contents and the parsed templates (in a kind of AST) to improve performance.</p>
<p>LiquidJS provides multiple ways to cache the parsed templates to improve performance.</p>
<h2 id="Programmatically" class="article-heading"><a href="#Programmatically" class="headerlink" title="Programmatically"></a>Programmatically<a class="article-anchor" href="#Programmatically" aria-hidden="true"></a></h2><p>The <a href="/api/classes/Liquid.html#parse">.parse()</a>, <a href="/api/classes/Liquid.html#parseFile">.parseFile()</a>, <a href="/api/classes/Liquid.html#parseFileSync">.parseFileSync()</a> APIs are used to parse templates from string or files. The result template can be then rendered multiple times with different context.</p>
<h2 id="Programmatically" class="article-heading"><a href="#Programmatically" class="headerlink" title="Programmatically"></a>Programmatically<a class="article-anchor" href="#Programmatically" aria-hidden="true"></a></h2><p>The <a href="/api/classes/Liquid.html#parse">.parse()</a>, <a href="/api/classes/Liquid.html#parseFile">.parseFile()</a>, <a href="/api/classes/Liquid.html#parseFileSync">.parseFileSync()</a> APIs are used to parse templates from strings or files. The resulting template can then be rendered multiple times with different context.</p>
<p>Parse from string:</p>
<pre class="line-numbers language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">var</span> tpl <span class="token operator">=</span> engine<span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span><span class="token string">'&#123;&#123;name | capitalize&#125;&#125;'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
@@ -130,7 +131,7 @@ engine<span class="token punctuation">.</span><span class="token function">rende
</div>
<footer class="article-footer">
<time class="article-footer-updated" datetime="2026-06-06T17:38:08.031Z" itemprop="dateModified">Last updated: 2026-06-06</time>
<time class="article-footer-updated" datetime="2026-06-07T16:27:07.442Z" itemprop="dateModified">Last updated: 2026-06-07</time>
<a href="use-in-expressjs.html" class="article-footer-prev" title="Use in Express.js"><i class="icon-chevron-left"></i><span>Prev</span></a><a href="escaping.html" class="article-footer-next" title="Escaping"><span>Next</span><i class="icon-chevron-right"></i></a>
</footer>
</div>
+2 -1
View File
@@ -39,6 +39,7 @@
<script src="https://cdn.cookiehub.eu/c2/e8e44c93.js"></script>
<script type="text/javascript">
document.addEventListener("DOMContentLoaded", function(event) {
if (location.hostname === 'localhost' || location.hostname === '127.0.0.1') return;
var cpm = {};
window.cookiehub.load(cpm);
});
@@ -861,7 +862,7 @@
</script></li></ul>
</div>
<footer class="article-footer">
<time class="article-footer-updated" datetime="2026-06-06T17:38:39.681Z" itemprop="dateModified">Last updated: 2026-06-06</time>
<time class="article-footer-updated" datetime="2026-06-07T16:27:36.846Z" itemprop="dateModified">Last updated: 2026-06-07</time>
<a href="migrate-to-9.html" class="article-footer-prev" title="Migrate to LiquidJS 9"><i class="icon-chevron-left"></i><span>Prev</span></a><a href="differences.html" class="article-footer-next" title="Differences with Shopify/liquid"><span>Next</span><i class="icon-chevron-right"></i></a>
</footer>
</div>
+4 -3
View File
@@ -39,6 +39,7 @@
<script src="https://cdn.cookiehub.eu/c2/e8e44c93.js"></script>
<script type="text/javascript">
document.addEventListener("DOMContentLoaded", function(event) {
if (location.hostname === 'localhost' || location.hostname === '127.0.0.1') return;
var cpm = {};
window.cookiehub.load(cpm);
});
@@ -104,14 +105,14 @@
<p><strong>Code Style</strong>: LiquidJS applies <a target="_blank" rel="noopener external nofollow noreferrer" href="https://github.com/standard/eslint-config-standard">standard</a> and <a target="_blank" rel="noopener external nofollow noreferrer" href="https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/src/configs/recommended.json">@typescript-eslint/recommended</a> rules.</p>
<p><strong>Testing</strong>: Make sure test cases pass with your patch merged by running <code>npm test</code></p>
<p><strong>Commit Message</strong>: Please align to <a target="_blank" rel="noopener external nofollow noreferrer" href="https://github.com/angular/angular.js/blob/master/DEVELOPERS.md#commits">the Angular Commit Message Guidelines</a>, especially note the <a target="_blank" rel="noopener external nofollow noreferrer" href="https://github.com/angular/angular.js/blob/master/DEVELOPERS.md#type">type identifier</a>, on which semantic-release bot depends.</p>
<p><strong>Backward-Compatibility</strong>: please be backward-compatible. LiquidJS is used by multiple layers of softwares, including underlying libraries, compilers, site generators and Web servers. Its not easy to do a major upgrade for most of them.</p>
<h2 id="Financial-Support" class="article-heading"><a href="#Financial-Support" class="headerlink" title="Financial Support"></a>Financial Support<a class="article-anchor" href="#Financial-Support" aria-hidden="true"></a></h2><p>LiquidJS is Open Source and Free. To help it live and thrive, especially when LiquidJS is benefiting your business, please consider contribute on <a target="_blank" rel="noopener external nofollow noreferrer" href="https://github.com/sponsors/harttle">GitHub Sponsors</a> or <a target="_blank" rel="noopener external nofollow noreferrer" href="https://opencollective.com/liquidjs/contribute/backer-10665/checkout">Open Collective</a>.</p>
<p><strong>Backward-Compatibility</strong>: please be backward-compatible. LiquidJS is used by multiple layers of software, including underlying libraries, compilers, site generators and Web servers. Its not easy to do a major upgrade for most of them.</p>
<h2 id="Financial-Support" class="article-heading"><a href="#Financial-Support" class="headerlink" title="Financial Support"></a>Financial Support<a class="article-anchor" href="#Financial-Support" aria-hidden="true"></a></h2><p>LiquidJS is Open Source and Free. To help it live and thrive, especially when LiquidJS is benefiting your business, consider contributing on <a target="_blank" rel="noopener external nofollow noreferrer" href="https://github.com/sponsors/harttle">GitHub Sponsors</a> or <a target="_blank" rel="noopener external nofollow noreferrer" href="https://opencollective.com/liquidjs/contribute/backer-10665/checkout">Open Collective</a>.</p>
<p>Ill add all financial contributors into <a target="_blank" rel="noopener external nofollow noreferrer" href="https://github.com/harttle/liquidjs#financial-support">README.md</a> and itll be also shown on <a href="https://liquidjs.com">https://liquidjs.com</a> after next GitHub Actions build.</p>
<p>If Im missing anything or you observed it not working, please dont hesitate to file an issue or find me via email (harttleharttle at gmail).</p>
</div>
<footer class="article-footer">
<time class="article-footer-updated" datetime="2026-06-06T17:38:08.031Z" itemprop="dateModified">Last updated: 2026-06-06</time>
<time class="article-footer-updated" datetime="2026-06-07T16:27:07.442Z" itemprop="dateModified">Last updated: 2026-06-07</time>
<a href="differences.html" class="article-footer-prev" title="Differences with Shopify/liquid"><i class="icon-chevron-left"></i><span>Prev</span></a>
</footer>
</div>
+5 -4
View File
@@ -39,6 +39,7 @@
<script src="https://cdn.cookiehub.eu/c2/e8e44c93.js"></script>
<script type="text/javascript">
document.addEventListener("DOMContentLoaded", function(event) {
if (location.hostname === 'localhost' || location.hostname === '127.0.0.1') return;
var cpm = {};
window.cookiehub.load(cpm);
});
@@ -99,7 +100,7 @@
</header>
<div class="article-content" itemprop="articleBody">
<h2 id="Compatibility" class="article-heading"><a href="#Compatibility" class="headerlink" title="Compatibility"></a>Compatibility<a class="article-anchor" href="#Compatibility" aria-hidden="true"></a></h2><p>Being compatible with the Ruby version is one of our priorities. Liquid language is originally <a target="_blank" rel="noopener external nofollow noreferrer" href="https://github.com/Shopify/liquid">implemented in Ruby</a> and used by Shopify and Jekyll (and thus GitHub Pages). As you can see its one of the most popular template engines in Ruby. Therere lots of people using LiquidJS to serve their templates originally written for Shopify themes and Jekyll sites.</p>
<h2 id="Compatibility" class="article-heading"><a href="#Compatibility" class="headerlink" title="Compatibility"></a>Compatibility<a class="article-anchor" href="#Compatibility" aria-hidden="true"></a></h2><p>Being compatible with the Ruby version is one of our priorities. Liquid language is originally <a target="_blank" rel="noopener external nofollow noreferrer" href="https://github.com/Shopify/liquid">implemented in Ruby</a> and used by Shopify and Jekyll (and thus GitHub Pages). As you can see its one of the most popular template engines in Ruby. There are lots of people using LiquidJS to serve their templates originally written for Shopify themes and Jekyll sites.</p>
<p>So “being compatible” means serving developers from Shopify and Jekyll well:</p>
<ul>
<li><strong>Well-formed Liquid template should work just fine in LiquidJS</strong>. For example, <code>forloop.index</code> should be 1-indexed, <code>nil</code> should be rendered as empty string rather than <code>undefined</code>, etc. Although some features (e.g. <a target="_blank" rel="noopener external nofollow noreferrer" href="https://github.com/harttle/liquidjs/issues/236">#236</a>) are not feasible in JavaScript, at least were trying to implement all the semantics of Liquid language.</li>
@@ -107,8 +108,8 @@
</ul>
<p>In the meantime, its now implemented in JavaScript, that means it has to be more powerful:</p>
<ul>
<li><strong>Async as first-class citizen</strong>. Filters and tags can be implemented asynchronously by return a <code>Promise</code>.</li>
<li><strong>Also can be sync</strong>. For scenarios that are not I/O intensive, render synchronously can be much faster. You can call synchronous APIs like <code>.renderSync()</code> as long as all the filters and tags in template support to be rendered synchronously. All builtin filters/tags support both sync and async render.</li>
<li><strong>Async as a first-class citizen</strong>. Filters and tags can be implemented asynchronously by returning a <code>Promise</code>.</li>
<li><strong>Can also be synchronous</strong>. For scenarios that are not I/O intensive, rendering synchronously can be much faster. You can call synchronous APIs like <code>.renderSync()</code> as long as all the filters and tags in the template can be rendered synchronously. All built-in filters/tags support both sync and async render.</li>
<li><strong><a href="https://liquidjs.com/tutorials/render-file.html#Abstract-File-System">Abstract file system</a></strong>. Along with async feature, LiquidJS can be used to serve templates stored in Databases <a target="_blank" rel="noopener external nofollow noreferrer" href="https://github.com/harttle/liquidjs/discussions/414">#414</a>, on remote HTTP server <a target="_blank" rel="noopener external nofollow noreferrer" href="https://github.com/harttle/liquidjs/discussions/485">#485</a>, and so on.</li>
<li><strong>Additional tags and filters</strong> like <code>layout</code> and <code>json</code>, <code>inspect</code>, <code>where_exp</code>, <code>group_by</code>, etc., see below for details.</li>
</ul>
@@ -134,7 +135,7 @@
</div>
<footer class="article-footer">
<time class="article-footer-updated" datetime="2026-06-06T17:38:08.031Z" itemprop="dateModified">Last updated: 2026-06-06</time>
<time class="article-footer-updated" datetime="2026-06-07T16:27:07.442Z" itemprop="dateModified">Last updated: 2026-06-07</time>
<a href="changelog.html" class="article-footer-prev" title="Changelog"><i class="icon-chevron-left"></i><span>Prev</span></a><a href="contribution-guidelines.html" class="article-footer-next" title="Contribution Guidelines"><span>Next</span><i class="icon-chevron-right"></i></a>
</footer>
</div>
+3 -2
View File
@@ -39,6 +39,7 @@
<script src="https://cdn.cookiehub.eu/c2/e8e44c93.js"></script>
<script type="text/javascript">
document.addEventListener("DOMContentLoaded", function(event) {
if (location.hostname === 'localhost' || location.hostname === '127.0.0.1') return;
var cpm = {};
window.cookiehub.load(cpm);
});
@@ -168,7 +169,7 @@ engine<span class="token punctuation">.</span><span class="token function">parse
<span class="token comment">// Outputs: "red"</span>
engine<span class="token punctuation">.</span><span class="token function">parseAndRender</span><span class="token punctuation">(</span><span class="token string">"&#123;&#123;color&#125;&#125;"</span><span class="token punctuation">,</span> context<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">html</span> <span class="token operator">=></span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>html<span class="token punctuation">)</span><span class="token punctuation">)</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<h2 id="toLiquid" class="article-heading"><a href="#toLiquid" class="headerlink" title="toLiquid"></a>toLiquid<a class="article-anchor" href="#toLiquid" aria-hidden="true"></a></h2><p><code>toLiquid()</code> is not a method of <code>Drop</code>, but it can be used to return a <code>Drop</code>. In cases where you have a fixed structure in the <code>context</code> that cannot change its values, you can implement <code>toLiquid()</code> to let LiquidJS use the returned value instead of itself to render the templates.</p>
<h2 id="toLiquid" class="article-heading"><a href="#toLiquid" class="headerlink" title="toLiquid"></a>toLiquid<a class="article-anchor" href="#toLiquid" aria-hidden="true"></a></h2><p><code>toLiquid()</code> is not a method of <code>Drop</code>, but it can be used to return a <code>Drop</code>. In cases where you have a fixed structure in the <code>context</code> that cannot change its values, you can implement <code>toLiquid()</code> to let LiquidJS use the returned value instead of the object itself when rendering templates.</p>
<pre class="line-numbers language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">import</span> <span class="token punctuation">&#123;</span> Liquid<span class="token punctuation">,</span> Drop <span class="token punctuation">&#125;</span> <span class="token keyword">from</span> <span class="token string">'liquidjs'</span>
<span class="token keyword">const</span> context <span class="token operator">=</span> <span class="token punctuation">&#123;</span>
@@ -244,7 +245,7 @@ engine<span class="token punctuation">.</span><span class="token function">parse
</div>
<footer class="article-footer">
<time class="article-footer-updated" datetime="2026-06-06T17:38:08.031Z" itemprop="dateModified">Last updated: 2026-06-06</time>
<time class="article-footer-updated" datetime="2026-06-07T16:27:07.442Z" itemprop="dateModified">Last updated: 2026-06-07</time>
<a href="render-tag-content.html" class="article-footer-prev" title="Render Tag Content"><i class="icon-chevron-left"></i><span>Prev</span></a><a href="sync-and-async.html" class="article-footer-next" title="Sync and Async"><span>Next</span><i class="icon-chevron-right"></i></a>
</footer>
</div>
+5 -4
View File
@@ -39,6 +39,7 @@
<script src="https://cdn.cookiehub.eu/c2/e8e44c93.js"></script>
<script type="text/javascript">
document.addEventListener("DOMContentLoaded", function(event) {
if (location.hostname === 'localhost' || location.hostname === '127.0.0.1') return;
var cpm = {};
window.cookiehub.load(cpm);
});
@@ -99,10 +100,10 @@
</header>
<div class="article-content" itemprop="articleBody">
<p>Escaping is important in all languages, including LiquidJS. While escaping has 2 different meanings for a template engine:</p>
<p>Escaping is important in all languages, including LiquidJS. Escaping has two different meanings for a template engine:</p>
<ol>
<li>Escaping for the output, i.e. HTML escape. Used to escape HTML special characters so the output will not break HTML structures, aka HTML safe.</li>
<li>Escaping for the language itself, i.e. Liquid escape. Used to output strings thats considered special in Liquid language. This will be useful when youre writing an article in Liquid template to introduce Liquid language.</li>
<li>Escaping for the language itself, i.e. Liquid escape. Used to output strings that are considered special in the Liquid language. This is useful when youre writing an article in a Liquid template to introduce the Liquid language.</li>
</ol>
<h2 id="HTML-Escape" class="article-heading"><a href="#HTML-Escape" class="headerlink" title="HTML Escape"></a>HTML Escape<a class="article-anchor" href="#HTML-Escape" aria-hidden="true"></a></h2><p>By default output is not escaped. While you can use <a href="../filters/escape.html">escape</a> filter for this:</p>
<p>Input</p>
@@ -132,7 +133,7 @@
<pre class="line-numbers language-text" data-language="text"><code class="language-text">In LiquidJS, &#123;&#123; this | escape &#125;&#125; will be HTML-escaped, but
&#123;&#123;&#123; that &#125;&#125;&#125; will not.<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre>
<p>Within strings literals in LiquidJS template, <code>\</code> can be used to escape special characters in string syntax. For example:</p>
<p>Within string literals in a LiquidJS template, <code>\</code> can be used to escape special characters in string syntax. For example:</p>
<p>Input</p>
<pre class="line-numbers language-liquid" data-language="liquid"><code class="language-liquid"><span class="token liquid language-liquid"><span class="token delimiter punctuation">&#123;&#123;</span> <span class="token string">"\"</span>" <span class="token delimiter punctuation">&#125;&#125;</span></span><span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre>
@@ -142,7 +143,7 @@
</div>
<footer class="article-footer">
<time class="article-footer-updated" datetime="2026-06-06T17:38:08.031Z" itemprop="dateModified">Last updated: 2026-06-06</time>
<time class="article-footer-updated" datetime="2026-06-07T16:27:07.442Z" itemprop="dateModified">Last updated: 2026-06-07</time>
<a href="caching.html" class="article-footer-prev" title="Caching"><i class="icon-chevron-left"></i><span>Prev</span></a><a href="register-filters-tags.html" class="article-footer-next" title="Register Filters/Tags"><span>Next</span><i class="icon-chevron-right"></i></a>
</footer>
</div>
+5 -4
View File
@@ -39,6 +39,7 @@
<script src="https://cdn.cookiehub.eu/c2/e8e44c93.js"></script>
<script type="text/javascript">
document.addEventListener("DOMContentLoaded", function(event) {
if (location.hostname === 'localhost' || location.hostname === '127.0.0.1') return;
var cpm = {};
window.cookiehub.load(cpm);
});
@@ -100,7 +101,7 @@
</header>
<div class="article-content" itemprop="articleBody">
<p>LiquidJS is a simple, expressive and safe <a target="_blank" rel="noopener external nofollow noreferrer" href="https://github.com/Shopify/liquid">Shopify</a> / GitHub Pages compatible template engine in pure JavaScript. The purpose of this repo is to provide a standard Liquid implementation for the JavaScript community. Liquid is originally implemented in Ruby and used by GitHub Pages, Jekyll and Shopify, see <a href="./differences.html">Differences with Shopify/liquid</a>.</p>
<p>LiquidJS syntax is relatively simple. Therere 2 types of markups in LiquidJS:</p>
<p>LiquidJS syntax is relatively simple. There are 2 types of markups in LiquidJS:</p>
<ul>
<li><strong>Tags</strong>. A tag consists of a tag name and optional arguments wrapped between <code>{%</code> and <code>%&#125;</code>.</li>
<li><strong>Outputs</strong>. An output consists of a value and a list of filters, which is optional, wrapped between <code>{{</code> and <code>&#125;&#125;</code>.</li>
@@ -118,21 +119,21 @@
<pre class="line-numbers language-liquid" data-language="liquid"><code class="language-liquid"><span class="token liquid language-liquid"><span class="token delimiter punctuation">&#123;&#123;</span> username <span class="token operator">|</span> <span class="token function filter">append</span><span class="token operator">:</span> <span class="token string">", welcome to LiquidJS!"</span> <span class="token operator">|</span> <span class="token function filter">capitalize</span> <span class="token delimiter punctuation">&#125;&#125;</span></span><span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre>
<p>A complete list of filters supported by LiquidJS can be found <a href="../filters/overview.html">here</a>.</p>
<h2 id="Tags" class="article-heading"><a href="#Tags" class="headerlink" title="Tags"></a>Tags<a class="article-anchor" href="#Tags" aria-hidden="true"></a></h2><p><strong>Tags</strong> are used to control the template rendering process, manipulating template variables, inter-op with other templates, etc. For example <code>assign</code> can be used to define a variable which can be later used in the template:</p>
<h2 id="Tags" class="article-heading"><a href="#Tags" class="headerlink" title="Tags"></a>Tags<a class="article-anchor" href="#Tags" aria-hidden="true"></a></h2><p><strong>Tags</strong> are used to control the template rendering process, manipulating template variables, interacting with other templates, etc. For example <code>assign</code> can be used to define a variable that can be later used in the template:</p>
<pre class="line-numbers language-liquid" data-language="liquid"><code class="language-liquid"><span class="token liquid language-liquid"><span class="token delimiter punctuation">&#123;%</span> <span class="token keyword">assign</span> foo <span class="token operator">=</span> <span class="token string">"FOO"</span> <span class="token delimiter punctuation">%&#125;</span></span><span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre>
<p>Typically tags appear in pairs with a start tag and a corresponding end tag. For example:</p>
<pre class="line-numbers language-liquid" data-language="liquid"><code class="language-liquid"><span class="token liquid language-liquid"><span class="token delimiter punctuation">&#123;%</span> <span class="token keyword">if</span> foo <span class="token operator">==</span> <span class="token string">"FOO"</span> <span class="token delimiter punctuation">%&#125;</span></span>
Variable `foo` equals "FOO"
<span class="token liquid language-liquid"><span class="token delimiter punctuation">&#123;%</span> <span class="token keyword">else</span> <span class="token delimiter punctuation">%&#125;</span></span>
Variable `foo` not equals "FOO"
Variable `foo` does not equal "FOO"
<span class="token liquid language-liquid"><span class="token delimiter punctuation">&#123;%</span> <span class="token keyword">endif</span> <span class="token delimiter punctuation">%&#125;</span></span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<p>A complete list of tags supported by LiquidJS can be found <a href="../tags/overview.html">here</a>.</p>
</div>
<footer class="article-footer">
<time class="article-footer-updated" datetime="2026-06-06T17:38:08.031Z" itemprop="dateModified">Last updated: 2026-06-06</time>
<time class="article-footer-updated" datetime="2026-06-07T16:27:07.442Z" itemprop="dateModified">Last updated: 2026-06-07</time>
<a href="setup.html" class="article-footer-next" title="Setup"><span>Next</span><i class="icon-chevron-right"></i></a>
</footer>
</div>
+5 -4
View File
@@ -39,6 +39,7 @@
<script src="https://cdn.cookiehub.eu/c2/e8e44c93.js"></script>
<script type="text/javascript">
document.addEventListener("DOMContentLoaded", function(event) {
if (location.hostname === 'localhost' || location.hostname === '127.0.0.1') return;
var cpm = {};
window.cookiehub.load(cpm);
});
@@ -99,7 +100,7 @@
</header>
<div class="article-content" itemprop="articleBody">
<p>LiquidJS 9 has some fundamental improvements, including bugfixes, new features and performance improvement due to higher target(see #137). Therere also some breaking changes.</p>
<p>LiquidJS 9 has some fundamental improvements, including bugfixes, new features and performance improvements due to a higher target (see #137). There are also some breaking changes.</p>
<h2 id="Features" class="article-heading"><a href="#Features" class="headerlink" title="Features"></a>Features<a class="article-anchor" href="#Features" aria-hidden="true"></a></h2><ul>
<li>Sync rendering: renderSync, parseAndRenderSync, renderFileSync</li>
<li>New utils: Expression</li>
@@ -108,10 +109,10 @@
<li>Rewrite boolean expression evaluation order, <a target="_blank" rel="noopener external nofollow noreferrer" href="https://github.com/harttle/liquidjs/issues/130">#130</a>;</li>
<li><code>break</code> and <code>continue</code> tags omitting output before them, <a target="_blank" rel="noopener external nofollow noreferrer" href="https://github.com/harttle/liquidjs/issues/123">#123</a>;</li>
<li>Fixes errors in React.js demo during yarn install, <a target="_blank" rel="noopener external nofollow noreferrer" href="https://github.com/harttle/liquidjs/issues/145">#145</a>;</li>
<li>Promise typed Drops are not await-ed some times.</li>
<li>Promise typed Drops are not always awaited.</li>
</ul>
<h2 id="Performance" class="article-heading"><a href="#Performance" class="headerlink" title="Performance"></a>Performance<a class="article-anchor" href="#Performance" aria-hidden="true"></a></h2><ul>
<li>Performance Improvements due to targeting to Node.js 8, see <a target="_blank" rel="noopener external nofollow noreferrer" href="https://github.com/harttle/liquidjs/issues/137">#137</a>;</li>
<li>Performance Improvements due to targeting Node.js 8, see <a target="_blank" rel="noopener external nofollow noreferrer" href="https://github.com/harttle/liquidjs/issues/137">#137</a>;</li>
<li>Memory footprint is reduced by 57.5%, see <a target="_blank" rel="noopener external nofollow noreferrer" href="https://github.com/harttle/liquidjs/pull/202">#202</a>;</li>
<li>Render performance is improved by 100.3%, see <a target="_blank" rel="noopener external nofollow noreferrer" href="https://github.com/harttle/liquidjs/pull/205">#205</a>.</li>
</ul>
@@ -123,7 +124,7 @@
</div>
<footer class="article-footer">
<time class="article-footer-updated" datetime="2026-06-06T17:38:08.031Z" itemprop="dateModified">Last updated: 2026-06-06</time>
<time class="article-footer-updated" datetime="2026-06-07T16:27:07.442Z" itemprop="dateModified">Last updated: 2026-06-07</time>
<a href="static-analysis.html" class="article-footer-prev" title="Static Analysis"><i class="icon-chevron-left"></i><span>Prev</span></a><a href="changelog.html" class="article-footer-next" title="Changelog"><span>Next</span><i class="icon-chevron-right"></i></a>
</footer>
</div>
+9 -8
View File
@@ -39,6 +39,7 @@
<script src="https://cdn.cookiehub.eu/c2/e8e44c93.js"></script>
<script type="text/javascript">
document.addEventListener("DOMContentLoaded", function(event) {
if (location.hostname === 'localhost' || location.hostname === '127.0.0.1') return;
var cpm = {};
window.cookiehub.load(cpm);
});
@@ -99,13 +100,13 @@
</header>
<div class="article-content" itemprop="articleBody">
<p>LiquidJS operators are very simple and different. Therere 2 types of operators supported:</p>
<p>LiquidJS operators are very simple and different. There are 2 types of operators supported:</p>
<ul>
<li>Comparison operators: <code>==</code>, <code>!=</code>, <code>&gt;</code>, <code>&lt;</code>, <code>&gt;=</code>, <code>&lt;=</code></li>
<li>Logic operators: <code>not</code>, <code>or</code>, <code>and</code>, <code>contains</code></li>
<li>Logical operators: <code>not</code>, <code>or</code>, <code>and</code>, <code>contains</code></li>
</ul>
<p>Thus numerical operators are not supported and you cannot even plus two numbers like this <code>{{a + b}}</code>, instead we need a filter <code>{{ a | plus: b}}</code>. Actually <code>+</code> is a valid variable name in LiquidJS.</p>
<h2 id="Logic-Operators" class="article-heading"><a href="#Logic-Operators" class="headerlink" title="Logic Operators"></a>Logic Operators<a class="article-anchor" href="#Logic-Operators" aria-hidden="true"></a></h2><h3 id="not" class="article-heading"><a href="#not" class="headerlink" title="not"></a>not<a class="article-anchor" href="#not" aria-hidden="true"></a></h3><p>Negates a condition. Returns <code>true</code> if the condition is false, and <code>false</code> if the condition is true.</p>
<p>Thus arithmetic operators are not supported and you cannot add two numbers like this <code>{{a + b}}</code>. Instead, use a filter: <code>{{ a | plus: b}}</code>. Actually <code>+</code> is a valid variable name in LiquidJS.</p>
<h2 id="Logical-Operators" class="article-heading"><a href="#Logical-Operators" class="headerlink" title="Logical Operators"></a>Logical Operators<a class="article-anchor" href="#Logical-Operators" aria-hidden="true"></a></h2><h3 id="not" class="article-heading"><a href="#not" class="headerlink" title="not"></a>not<a class="article-anchor" href="#not" aria-hidden="true"></a></h3><p>Negates a condition. Returns <code>true</code> if the condition is false, and <code>false</code> if the condition is true.</p>
<p>Input</p>
<pre class="line-numbers language-liquid" data-language="liquid"><code class="language-liquid"><span class="token liquid language-liquid"><span class="token delimiter punctuation">&#123;%</span> <span class="token keyword">if</span> not user<span class="token punctuation">.</span>active <span class="token delimiter punctuation">%&#125;</span></span>
User is inactive
@@ -132,13 +133,13 @@
<h2 id="Precedence" class="article-heading"><a href="#Precedence" class="headerlink" title="Precedence"></a>Precedence<a class="article-anchor" href="#Precedence" aria-hidden="true"></a></h2><ol>
<li>Comparison operators, and <code>contains</code>. All comparison operators alongside <code>contains</code> have the same (highest) precedence.</li>
<li><code>not</code> operator. It has slightly more precedence than <code>or</code> and <code>and</code>.</li>
<li><code>or</code> and <code>and</code> operators. These logic operators have the same (lowest) precedence.</li>
<li><code>or</code> and <code>and</code> operators. These logical operators have the same (lowest) precedence.</li>
</ol>
<h2 id="Associativity" class="article-heading"><a href="#Associativity" class="headerlink" title="Associativity"></a>Associativity<a class="article-anchor" href="#Associativity" aria-hidden="true"></a></h2><p>Logic operators are evaluated from right to left, see <a target="_blank" rel="noopener external nofollow noreferrer" href="https://shopify.dev/docs/api/liquid/basics#order-of-operations">shopify docs</a>.</p>
<h2 id="Associativity" class="article-heading"><a href="#Associativity" class="headerlink" title="Associativity"></a>Associativity<a class="article-anchor" href="#Associativity" aria-hidden="true"></a></h2><p>Logical operators are evaluated from right to left, see <a target="_blank" rel="noopener external nofollow noreferrer" href="https://shopify.dev/docs/api/liquid/basics#order-of-operations">shopify docs</a>.</p>
</div>
<footer class="article-footer">
<time class="article-footer-updated" datetime="2026-06-06T17:38:08.031Z" itemprop="dateModified">Last updated: 2026-06-06</time>
<time class="article-footer-updated" datetime="2026-06-07T16:27:07.442Z" itemprop="dateModified">Last updated: 2026-06-07</time>
<a href="plugins.html" class="article-footer-prev" title="Plugins"><i class="icon-chevron-left"></i><span>Prev</span></a><a href="truthy-and-falsy.html" class="article-footer-next" title="Truthy and Falsy"><span>Next</span><i class="icon-chevron-right"></i></a>
</footer>
</div>
@@ -147,7 +148,7 @@
<div id="article-toc-inner">
<div id="article-toc-inner-list">
<strong class="sidebar-title">Contents</strong>
<ol class="toc"><li class="toc-item toc-level-2"><a class="toc-link" href="#Logic-Operators"><span class="toc-text">Logic Operators</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#not"><span class="toc-text">not</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#and"><span class="toc-text">and</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#or"><span class="toc-text">or</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#contains"><span class="toc-text">contains</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#Precedence"><span class="toc-text">Precedence</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#Associativity"><span class="toc-text">Associativity</span></a></li></ol>
<ol class="toc"><li class="toc-item toc-level-2"><a class="toc-link" href="#Logical-Operators"><span class="toc-text">Logical Operators</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#not"><span class="toc-text">not</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#and"><span class="toc-text">and</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#or"><span class="toc-text">or</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#contains"><span class="toc-text">contains</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#Precedence"><span class="toc-text">Precedence</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#Associativity"><span class="toc-text">Associativity</span></a></li></ol>
</div>
<a href="#" id="article-toc-top">Back to Top</a>
</div>
+15 -14
View File
@@ -39,6 +39,7 @@
<script src="https://cdn.cookiehub.eu/c2/e8e44c93.js"></script>
<script type="text/javascript">
document.addEventListener("DOMContentLoaded", function(event) {
if (location.hostname === 'localhost' || location.hostname === '127.0.0.1') return;
var cpm = {};
window.cookiehub.load(cpm);
});
@@ -105,16 +106,16 @@
<span class="token literal-property property">cache</span><span class="token operator">:</span> <span class="token boolean">true</span>
<span class="token punctuation">&#125;</span><span class="token punctuation">)</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span></span></code></pre>
<blockquote class="note info"><strong class="note-title">API Document</strong><p>Following is an overview for all the options, for exact types and signatures please refer to <a href="https://liquidjs.com/api/interfaces/LiquidOptions.html" target="_self">LiquidOptions | API</a>.</p>
<blockquote class="note info"><strong class="note-title">API documentation</strong><p>Following is an overview for all the options. For exact types and signatures, see <a href="https://liquidjs.com/api/interfaces/LiquidOptions.html" target="_self">LiquidOptions | API</a>.</p>
</blockquote>
<h2 id="cache" class="article-heading"><a href="#cache" class="headerlink" title="cache"></a>cache<a class="article-anchor" href="#cache" aria-hidden="true"></a></h2><p><strong>cache</strong> is used to improve performance by caching previously parsed template structures, specially in cases when were repeatedly parse or render files.</p>
<p>Its default to <code>false</code>. When setting to <code>true</code> a default LRU cache of size 1024 will be enabled. And certainly it can be a number which indicates the size of cache you want.</p>
<h2 id="cache" class="article-heading"><a href="#cache" class="headerlink" title="cache"></a>cache<a class="article-anchor" href="#cache" aria-hidden="true"></a></h2><p><strong>cache</strong> is used to improve performance by caching previously parsed template structures, especially in cases when we repeatedly parse or render files.</p>
<p>It defaults to <code>false</code>. When set to <code>true</code>, a default LRU cache of size 1024 will be enabled. It can also be a number indicating the cache size you want.</p>
<p>Additionally, it can also be a custom cache implementation. See <a href="./caching.html">Caching</a> for details.</p>
<h2 id="Partials-Layouts" class="article-heading"><a href="#Partials-Layouts" class="headerlink" title="Partials/Layouts"></a>Partials/Layouts<a class="article-anchor" href="#Partials-Layouts" aria-hidden="true"></a></h2><p><strong>root</strong> is used to specify template directories for LiquidJS to lookup and read template files. Can be a single string and an array of strings. See <a href="./render-file.html">Render Files</a> for details.</p>
<p><strong>layouts</strong> is used to specify template directories for LiquidJS to lookup files for <code>&#123;% layout %&#125;</code>. Same format as <code>root</code> and will default to <code>root</code> if not specified.</p>
<p><strong>partials</strong> is used to specify template directories for LiquidJS to lookup files for <code>&#123;% render %&#125;</code> and <code>&#123;% include %&#125;</code>. Same format as <code>root</code> and will default to <code>root</code> if not specified.</p>
<p><strong>relativeReference</strong> is set to <code>true</code> by default to allow relative filenames. Note that relatively referenced files are also need to be within corresponding root. For example you can reference another file like <code>&#123;% render ../foo/bar %&#125;</code> as long as <code>../foo/bar</code> is also within <code>partials</code> directory.</p>
<h2 id="Partials-Layouts" class="article-heading"><a href="#Partials-Layouts" class="headerlink" title="Partials/Layouts"></a>Partials/Layouts<a class="article-anchor" href="#Partials-Layouts" aria-hidden="true"></a></h2><p><strong>root</strong> is used to specify template directories for LiquidJS to look up and read template files. Can be a single string or an array of strings. See <a href="./render-file.html">Render Files</a> for details.</p>
<p><strong>layouts</strong> is used to specify template directories for LiquidJS to look up files for <code>&#123;% layout %&#125;</code>. Same format as <code>root</code> and will default to <code>root</code> if not specified.</p>
<p><strong>partials</strong> is used to specify template directories for LiquidJS to look up files for <code>&#123;% render %&#125;</code> and <code>&#123;% include %&#125;</code>. Same format as <code>root</code> and will default to <code>root</code> if not specified.</p>
<p><strong>relativeReference</strong> is set to <code>true</code> by default to allow relative filenames. Note that relatively referenced files also need to be within the corresponding root. For example you can reference another file like <code>&#123;% render ../foo/bar %&#125;</code> as long as <code>../foo/bar</code> is also within <code>partials</code> directory.</p>
<h2 id="dynamicPartials" class="article-heading"><a href="#dynamicPartials" class="headerlink" title="dynamicPartials"></a>dynamicPartials<a class="article-anchor" href="#dynamicPartials" aria-hidden="true"></a></h2><blockquote>
<p>Note: for historical reasons, its named dynamicPartials but it also works for layouts.</p>
</blockquote>
@@ -135,7 +136,7 @@
<li>Use <code>=</code> instead of <code>:</code> to separate parameter key-values.</li>
<li>Parameters are under <code>include</code> variable instead of current scope.</li>
</ul>
<p>For example in the following template, <code>name.html</code> is not quoted, <code>header</code> and <code>&quot;HEADER&quot;</code> are separated by <code>=</code>, and the <code>header</code> parameter is referenced by <code>include.header</code>. More details please check out <a href="../tags/include.html">include</a>.</p>
<p>For example in the following template, <code>name.html</code> is not quoted, <code>header</code> and <code>&quot;HEADER&quot;</code> are separated by <code>=</code>, and the <code>header</code> parameter is referenced by <code>include.header</code>. For more details, see <a href="../tags/include.html">include</a>.</p>
<pre class="line-numbers language-liquid" data-language="liquid"><code class="language-liquid">// entry template
<span class="token liquid language-liquid"><span class="token delimiter punctuation">&#123;%</span> <span class="token keyword">include</span> <span class="token object">article</span><span class="token punctuation">.</span>html header<span class="token operator">=</span><span class="token string">"HEADER"</span> content<span class="token operator">=</span><span class="token string">"CONTENT"</span> <span class="token delimiter punctuation">%&#125;</span></span>
@@ -152,18 +153,18 @@
<blockquote class="note info"><strong class="note-title">Legacy Versions</strong><p>Before 2.0.1, <code>extname</code> is set to <code>.liquid</code> by default. To change that you need to set <code>extname: ''</code> explicitly. See <a href="https://github.com/harttle/liquidjs/issues/41" rel="external nofollow noreferrer" target="_blank">#41</a> for details.</p>
</blockquote>
<h2 id="fs" class="article-heading"><a href="#fs" class="headerlink" title="fs"></a>fs<a class="article-anchor" href="#fs" aria-hidden="true"></a></h2><p><strong>fs</strong> is used to define a custom file system implementation which will be used by LiquidJS to lookup and read template files. See <a href="./render-file.html#Abstract-File-System">Abstract File System</a> for details.</p>
<h2 id="fs" class="article-heading"><a href="#fs" class="headerlink" title="fs"></a>fs<a class="article-anchor" href="#fs" aria-hidden="true"></a></h2><p><strong>fs</strong> is used to define a custom file system implementation which will be used by LiquidJS to look up and read template files. See <a href="./render-file.html#Abstract-File-System">Abstract File System</a> for details.</p>
<h2 id="globals" class="article-heading"><a href="#globals" class="headerlink" title="globals"></a>globals<a class="article-anchor" href="#globals" aria-hidden="true"></a></h2><p><strong>globals</strong> is used to define global variables available to all templates even in cases of <a href="../tags/render.html">render tag</a>. See <a target="_blank" rel="noopener external nofollow noreferrer" href="https://github.com/harttle/liquidjs/issues/185">3185</a> for details.</p>
<h2 id="jsTruthy" class="article-heading"><a href="#jsTruthy" class="headerlink" title="jsTruthy"></a>jsTruthy<a class="article-anchor" href="#jsTruthy" aria-hidden="true"></a></h2><p><strong>jsTruthy</strong> is used to use standard JavaScript truthiness rather than the Shopify.</p>
<p>it defaults to false. For example, when set to true, a blank string would evaluate to false with jsTruthy. With Shopifys truthiness, a blank string is true.</p>
<h2 id="jsTruthy" class="article-heading"><a href="#jsTruthy" class="headerlink" title="jsTruthy"></a>jsTruthy<a class="article-anchor" href="#jsTruthy" aria-hidden="true"></a></h2><p><strong>jsTruthy</strong> is used to use standard JavaScript truthiness rather than Shopifys.</p>
<p>It defaults to <code>false</code>. For example, when set to <code>true</code>, a blank string would evaluate to false with jsTruthy. With Shopifys truthiness, a blank string is true.</p>
<h2 id="outputEscape" class="article-heading"><a href="#outputEscape" class="headerlink" title="outputEscape"></a>outputEscape<a class="article-anchor" href="#outputEscape" aria-hidden="true"></a></h2><p><a href="/api/interfaces/LiquidOptions.html#outputEscape">outputEscape</a> can be used to automatically escape output strings. It can be one of <code>&quot;escape&quot;</code>, <code>&quot;json&quot;</code>, or <code>(val: unknown) =&gt; string</code>, defaults to <code>undefined</code>.</p>
<ul>
<li>For untrusted output variables, set <code>outputEscape: &quot;escape&quot;</code> makes them be HTML escaped by default. Youll need <a href="../filters/raw.html">raw</a> filter for direct output.</li>
<li><code>&quot;json&quot;</code> is useful when youre using LiquidJS to create valid JSON files.</li>
<li>It can even be a function which allows you to control what variables are output throughout LiquidJS. Please note the input can be any type other than string, e.g. an filter returned an non-string value.</li>
<li>It can even be a function that allows you to control what variables are output throughout LiquidJS. Please note the input can be any type other than string, e.g. a filter may return a non-string value.</li>
</ul>
<h2 id="Date" class="article-heading"><a href="#Date" class="headerlink" title="Date"></a>Date<a class="article-anchor" href="#Date" aria-hidden="true"></a></h2><p><strong>timezoneOffset</strong> is used to specify a different timezone to output dates, your local timezone will be used if not specified. For example, set <code>timezoneOffset: 0</code> to output all dates in UTC/GMT 00:00.</p>
<p><strong>preserveTimezones</strong> is a boolean effects only literal timestamps. When set to <code>true</code>, all literal timestamps will remain the same when output. This is a parser option, so Date objects passed to LiquidJS as data will not be affected. Note that <code>preserveTimezones</code> has a higher priority than <code>timezoneOffset</code>.</p>
<p><strong>preserveTimezones</strong> is a boolean that affects only literal timestamps. When set to <code>true</code>, all literal timestamps will remain the same when output. This is a parser option, so Date objects passed to LiquidJS as data will not be affected. Note that <code>preserveTimezones</code> has a higher priority than <code>timezoneOffset</code>.</p>
<p><strong>dateFormat</strong> is used to specify a default format to output dates. <code>%A, %B %-e, %Y at %-l:%M %P %z</code> will be used if not specified. For example, set <code>dateFormat: %Y-%m-%dT%H:%M:%S:%LZ</code> to output all dates in <a target="_blank" rel="noopener external nofollow noreferrer" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toJSON">JavaScript Date.toJson()</a> format.</p>
<h2 id="Trimming" class="article-heading"><a href="#Trimming" class="headerlink" title="Trimming"></a>Trimming<a class="article-anchor" href="#Trimming" aria-hidden="true"></a></h2><p><strong>greedy</strong>, <strong>trimOutputLeft</strong>, <strong>trimOutputRight</strong>, <strong>trimTagLeft</strong>, <strong>trimTagRight</strong> options are used to eliminate extra newlines and indents in templates around Liquid Constructs. See <a href="./whitespace-control.html">Whitespace Control</a> for details.</p>
<h2 id="Delimiter" class="article-heading"><a href="#Delimiter" class="headerlink" title="Delimiter"></a>Delimiter<a class="article-anchor" href="#Delimiter" aria-hidden="true"></a></h2><p><strong>outputDelimiterLeft</strong>, <strong>outputDelimiterRight</strong>, <strong>tagDelimiterLeft</strong>, <strong>tagDelimiterRight</strong> are used to customize the delimiters for LiquidJS <a href="./intro-to-liquid.html">Tags and Filters</a>. For example with <code>outputDelimiterLeft: &lt;%=, outputDelimiterRight: %&gt;</code> we are able to avoid conflicts with other languages:</p>
@@ -180,7 +181,7 @@
</div>
<footer class="article-footer">
<time class="article-footer-updated" datetime="2026-06-06T17:38:08.031Z" itemprop="dateModified">Last updated: 2026-06-06</time>
<time class="article-footer-updated" datetime="2026-06-07T16:27:07.442Z" itemprop="dateModified">Last updated: 2026-06-07</time>
<a href="setup.html" class="article-footer-prev" title="Setup"><i class="icon-chevron-left"></i><span>Prev</span></a><a href="render-file.html" class="article-footer-next" title="Render Files"><span>Next</span><i class="icon-chevron-right"></i></a>
</footer>
</div>
+4 -3
View File
@@ -39,6 +39,7 @@
<script src="https://cdn.cookiehub.eu/c2/e8e44c93.js"></script>
<script type="text/javascript">
document.addEventListener("DOMContentLoaded", function(event) {
if (location.hostname === 'localhost' || location.hostname === '127.0.0.1') return;
var cpm = {};
window.cookiehub.load(cpm);
});
@@ -99,7 +100,7 @@
</header>
<div class="article-content" itemprop="articleBody">
<h2 id="Access-Raw-Parameters" class="article-heading"><a href="#Access-Raw-Parameters" class="headerlink" title="Access Raw Parameters"></a>Access Raw Parameters<a class="article-anchor" href="#Access-Raw-Parameters" aria-hidden="true"></a></h2><p>As covered in <a href="/tutorials/register-filters-tags.html">Register Filters/Tags</a>, tag parameters is available on <code>tagToken.args</code> as a raw string. For example:</p>
<h2 id="Access-Raw-Parameters" class="article-heading"><a href="#Access-Raw-Parameters" class="headerlink" title="Access Raw Parameters"></a>Access Raw Parameters<a class="article-anchor" href="#Access-Raw-Parameters" aria-hidden="true"></a></h2><p>As covered in <a href="/tutorials/register-filters-tags.html">Register Filters/Tags</a>, tag parameters are available on <code>tagToken.args</code> as a raw string. For example:</p>
<pre class="line-numbers language-javascript" data-language="javascript"><code class="language-javascript"><span class="token comment">// Usage: &#123;% random foo bar coo %&#125;</span>
<span class="token comment">// Output: "foo", "bar" or "coo"</span>
engine<span class="token punctuation">.</span><span class="token function">registerTag</span><span class="token punctuation">(</span><span class="token string">'random'</span><span class="token punctuation">,</span> <span class="token punctuation">&#123;</span>
@@ -144,7 +145,7 @@ engine<span class="token punctuation">.</span><span class="token function">regis
<blockquote class="note info"><strong class="note-title">Async and Promises</strong><p>Async calls in LiquidJS are implemented by generators directly, for we can call generators in synchronous manner so this tag implementation is also valid for <code>renderSync()</code>, <code>parseAndRenderSync()</code>, <code>renderFileSync()</code>. If you need to await a promise in tag implementation, simply replace <code>await somePromise</code> with <code>yield somePromise</code> and keep <code>* render()</code> instead of <code>async render()</code> will do the trick. See <a href="/tutorials/sync-and-async.html">Sync and Async</a> for more details.</p>
</blockquote>
<h2 id="Parse-Key-Value-Pairs-as-Named-Parameters" class="article-heading"><a href="#Parse-Key-Value-Pairs-as-Named-Parameters" class="headerlink" title="Parse Key-Value Pairs as Named Parameters"></a>Parse Key-Value Pairs as Named Parameters<a class="article-anchor" href="#Parse-Key-Value-Pairs-as-Named-Parameters" aria-hidden="true"></a></h2><p>Named parameters become very handy when therere optional parameters or lots of parameters, in which case the order of parameters is not important. This is exactly what <a href="/api/classes/Hash.html">Hash</a> class is invented for.</p>
<h2 id="Parse-Key-Value-Pairs-as-Named-Parameters" class="article-heading"><a href="#Parse-Key-Value-Pairs-as-Named-Parameters" class="headerlink" title="Parse Key-Value Pairs as Named Parameters"></a>Parse Key-Value Pairs as Named Parameters<a class="article-anchor" href="#Parse-Key-Value-Pairs-as-Named-Parameters" aria-hidden="true"></a></h2><p>Named parameters become very handy when there are optional parameters or lots of parameters, in which case the order of parameters is not important. This is exactly what the <a href="/api/classes/Hash.html">Hash</a> class was invented for.</p>
<pre class="line-numbers language-liquid" data-language="liquid"><code class="language-liquid"><span class="token liquid language-liquid"><span class="token delimiter punctuation">&#123;%</span> random from<span class="token operator">:</span><span class="token number">2</span><span class="token punctuation">,</span> to<span class="token operator">:</span>max <span class="token delimiter punctuation">%&#125;</span></span><span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre>
<p>In the above example, were trying to generate a random number in the range [2, max]. Well use <code>Hash</code> to parse <code>from</code> and <code>to</code> parameters.</p>
@@ -168,7 +169,7 @@ engine<span class="token punctuation">.</span><span class="token function">regis
</div>
<footer class="article-footer">
<time class="article-footer-updated" datetime="2026-06-06T17:38:08.031Z" itemprop="dateModified">Last updated: 2026-06-06</time>
<time class="article-footer-updated" datetime="2026-06-07T16:27:07.442Z" itemprop="dateModified">Last updated: 2026-06-07</time>
<a href="access-scope-in-filters.html" class="article-footer-prev" title="Access Scope in Filters"><i class="icon-chevron-left"></i><span>Prev</span></a><a href="render-tag-content.html" class="article-footer-next" title="Render Tag Content"><span>Next</span><i class="icon-chevron-right"></i></a>
</footer>
</div>
+4 -3
View File
@@ -39,6 +39,7 @@
<script src="https://cdn.cookiehub.eu/c2/e8e44c93.js"></script>
<script type="text/javascript">
document.addEventListener("DOMContentLoaded", function(event) {
if (location.hostname === 'localhost' || location.hostname === '127.0.0.1') return;
var cpm = {};
window.cookiehub.load(cpm);
});
@@ -114,7 +115,7 @@ color: &#39;&#123;&#123; color &#125;&#125;&#39; shape: &#39;&#123;&#123; shape
color: &#39;red&#39; shape: &#39;circle&#39;
color: &#39;yellow&#39; shape: &#39;square&#39;<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span></span></code></pre>
<p>More details please refer to the <a href="../tags/render.html">render</a> tag.</p>
<p>For more details, see the <a href="../tags/render.html">render</a> tag.</p>
<blockquote class="note tip"><strong class="note-title">The &quot;.liquid&quot; Extension</strong><p>The “.liquid” extension in <code>layout</code>, <code>render</code> and <code>include</code> can be omitted if Liquid instance is created using <code>extname: &quot;.liquid&quot;</code> option. See <a href="./options.html#extname">the extname option</a> for details.</p>
</blockquote>
@@ -133,11 +134,11 @@ Footer
My page content
Footer<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span></span></code></pre>
<p>More details please refer to the <a href="../tags/layout.html">layout</a> tag.</p>
<p>For more details, see the <a href="../tags/layout.html">layout</a> tag.</p>
</div>
<footer class="article-footer">
<time class="article-footer-updated" datetime="2026-06-06T17:38:08.031Z" itemprop="dateModified">Last updated: 2026-06-06</time>
<time class="article-footer-updated" datetime="2026-06-07T16:27:07.442Z" itemprop="dateModified">Last updated: 2026-06-07</time>
<a href="render-file.html" class="article-footer-prev" title="Render Files"><i class="icon-chevron-left"></i><span>Prev</span></a><a href="use-in-expressjs.html" class="article-footer-next" title="Use in Express.js"><span>Next</span><i class="icon-chevron-right"></i></a>
</footer>
</div>
+4 -3
View File
@@ -39,6 +39,7 @@
<script src="https://cdn.cookiehub.eu/c2/e8e44c93.js"></script>
<script type="text/javascript">
document.addEventListener("DOMContentLoaded", function(event) {
if (location.hostname === 'localhost' || location.hostname === '127.0.0.1') return;
var cpm = {};
window.cookiehub.load(cpm);
});
@@ -100,8 +101,8 @@
</header>
<div class="article-content" itemprop="articleBody">
<p>A number of tags and filters can be encapsulated into a <strong>plugin</strong>, which will be typically installed via npm. This article provides information about how to create and use a plugin.</p>
<h2 id="Write-a-Plugin" class="article-heading"><a href="#Write-a-Plugin" class="headerlink" title="Write a Plugin"></a>Write a Plugin<a class="article-anchor" href="#Write-a-Plugin" aria-hidden="true"></a></h2><p>A liquidjs plugin is simple function which takes the <a href="/api/classes/Liquid.html">Liquid class</a> as the first parameter and the Liquid instance for <code>this</code>. We can call liquidjs APIs on <code>this</code> to make certain changes, especially <a href="/harttle/liquidjs/wiki/Register-Filters-Tags">register filters and tags</a>.</p>
<p>Now well make a plugin to upper case every letter of the input, save the following snippet to <code>upup.js</code>:</p>
<h2 id="Write-a-Plugin" class="article-heading"><a href="#Write-a-Plugin" class="headerlink" title="Write a Plugin"></a>Write a Plugin<a class="article-anchor" href="#Write-a-Plugin" aria-hidden="true"></a></h2><p>A LiquidJS plugin is a simple function that takes the <a href="/api/classes/Liquid.html">Liquid class</a> as the first parameter and uses the Liquid instance for <code>this</code>. We can call LiquidJS APIs on <code>this</code> to make certain changes, especially <a href="/harttle/liquidjs/wiki/Register-Filters-Tags">register filters and tags</a>.</p>
<p>Now well make a plugin to uppercase every letter of the input. Save the following snippet to <code>upup.js</code>:</p>
<pre class="line-numbers language-javascript" data-language="javascript"><code class="language-javascript"><span class="token comment">/**
* Inside the plugin function, `this` refers to the Liquid instance.
*
@@ -128,7 +129,7 @@ engine
</div>
<footer class="article-footer">
<time class="article-footer-updated" datetime="2026-06-06T17:38:08.031Z" itemprop="dateModified">Last updated: 2026-06-06</time>
<time class="article-footer-updated" datetime="2026-06-07T16:27:07.442Z" itemprop="dateModified">Last updated: 2026-06-07</time>
<a href="whitespace-control.html" class="article-footer-prev" title="Whitespace Control"><i class="icon-chevron-left"></i><span>Prev</span></a><a href="operators.html" class="article-footer-next" title="Operators"><span>Next</span><i class="icon-chevron-right"></i></a>
</footer>
</div>
+3 -2
View File
@@ -39,6 +39,7 @@
<script src="https://cdn.cookiehub.eu/c2/e8e44c93.js"></script>
<script type="text/javascript">
document.addEventListener("DOMContentLoaded", function(event) {
if (location.hostname === 'localhost' || location.hostname === '127.0.0.1') return;
var cpm = {};
window.cookiehub.load(cpm);
});
@@ -141,7 +142,7 @@ engine<span class="token punctuation">.</span><span class="token function">regis
engine<span class="token punctuation">.</span><span class="token function">registerFilter</span><span class="token punctuation">(</span><span class="token string">'add'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">initial<span class="token punctuation">,</span> arg1<span class="token punctuation">,</span> arg2</span><span class="token punctuation">)</span> <span class="token operator">=></span> initial <span class="token operator">+</span> arg1 <span class="token operator">+</span> arg2<span class="token punctuation">)</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre>
<p>See existing filter implementations here: <a target="_blank" rel="noopener external nofollow noreferrer" href="https://github.com/harttle/liquidjs/tree/master/src/filters">https://github.com/harttle/liquidjs/tree/master/src/filters</a></p>
<h2 id="Unregister-Tags-Filters" class="article-heading"><a href="#Unregister-Tags-Filters" class="headerlink" title="Unregister Tags/Filters"></a>Unregister Tags/Filters<a class="article-anchor" href="#Unregister-Tags-Filters" aria-hidden="true"></a></h2><p>In some cases its desirable to disable some tags/filters (see <a target="_blank" rel="noopener external nofollow noreferrer" href="https://github.com/harttle/liquidjs/issues/324">#324</a>), youll need to register a dummy tag/filter in which an corresponding Error throws.</p>
<h2 id="Unregister-Tags-Filters" class="article-heading"><a href="#Unregister-Tags-Filters" class="headerlink" title="Unregister Tags/Filters"></a>Unregister Tags/Filters<a class="article-anchor" href="#Unregister-Tags-Filters" aria-hidden="true"></a></h2><p>In some cases its desirable to disable some tags/filters (see <a target="_blank" rel="noopener external nofollow noreferrer" href="https://github.com/harttle/liquidjs/issues/324">#324</a>). Youll need to register a dummy tag/filter that throws a corresponding Error.</p>
<pre class="line-numbers language-javascript" data-language="javascript"><code class="language-javascript"><span class="token comment">// disable a tag</span>
<span class="token keyword">const</span> disabledTag <span class="token operator">=</span> <span class="token punctuation">&#123;</span>
<span class="token function-variable function">parse</span><span class="token operator">:</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">token</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
@@ -160,7 +161,7 @@ engine<span class="token punctuation">.</span><span class="token function">regis
</div>
<footer class="article-footer">
<time class="article-footer-updated" datetime="2026-06-06T17:38:08.031Z" itemprop="dateModified">Last updated: 2026-06-06</time>
<time class="article-footer-updated" datetime="2026-06-07T16:27:07.442Z" itemprop="dateModified">Last updated: 2026-06-07</time>
<a href="escaping.html" class="article-footer-prev" title="Escaping"><i class="icon-chevron-left"></i><span>Prev</span></a><a href="access-scope-in-filters.html" class="article-footer-next" title="Access Scope in Filters"><span>Next</span><i class="icon-chevron-right"></i></a>
</footer>
</div>
+4 -3
View File
@@ -39,6 +39,7 @@
<script src="https://cdn.cookiehub.eu/c2/e8e44c93.js"></script>
<script type="text/javascript">
document.addEventListener("DOMContentLoaded", function(event) {
if (location.hostname === 'localhost' || location.hostname === '127.0.0.1') return;
var cpm = {};
window.cookiehub.load(cpm);
});
@@ -120,7 +121,7 @@ engine
<pre class="line-numbers language-none"><code class="language-none">&gt; node index.js
name: alice<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre>
<h2 id="Template-Lookup" class="article-heading"><a href="#Template-Lookup" class="headerlink" title="Template Lookup"></a>Template Lookup<a class="article-anchor" href="#Template-Lookup" aria-hidden="true"></a></h2><p>Template files names passed to <a href="/api/classes/Liquid.html#renderFile">renderFile</a>, <a href="/api/classes/Liquid.html#parseFile">parseFile</a>, <a href="/api/classes/Liquid.html#renderFileSync">renderFileSync</a>, <a href="/api/classes/Liquid.html#parseFileSync">parseFileSync</a> APIs,<br>and <a target="_blank" rel="noopener external nofollow noreferrer" href="https://help.shopify.com/themes/liquid/tags/theme-tags#include">include</a>, <a target="_blank" rel="noopener external nofollow noreferrer" href="https://help.shopify.com/en/themes/liquid/tags/theme-tags#layout">layout</a> tags are resolved against <a href="/api/interfaces/LiquidOptions.html#root">the root option</a>.</p>
<h2 id="Template-Lookup" class="article-heading"><a href="#Template-Lookup" class="headerlink" title="Template Lookup"></a>Template Lookup<a class="article-anchor" href="#Template-Lookup" aria-hidden="true"></a></h2><p>Template file names passed to <a href="/api/classes/Liquid.html#renderFile">renderFile</a>, <a href="/api/classes/Liquid.html#parseFile">parseFile</a>, <a href="/api/classes/Liquid.html#renderFileSync">renderFileSync</a>, <a href="/api/classes/Liquid.html#parseFileSync">parseFileSync</a> APIs,<br>and <a target="_blank" rel="noopener external nofollow noreferrer" href="https://help.shopify.com/themes/liquid/tags/theme-tags#include">include</a>, <a target="_blank" rel="noopener external nofollow noreferrer" href="https://help.shopify.com/en/themes/liquid/tags/theme-tags#layout">layout</a> tags are resolved against <a href="/api/interfaces/LiquidOptions.html#root">the root option</a>.</p>
<p>It can be a string-typed path (see above example), or a list of root directories, in which case templates will be looked up in that order. e.g.</p>
<pre class="line-numbers language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">var</span> engine <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Liquid</span><span class="token punctuation">(</span><span class="token punctuation">&#123;</span>
<span class="token literal-property property">root</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'views/'</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
@@ -167,7 +168,7 @@ name: alice<span aria-hidden="true" class="line-numbers-rows"><span></span><span
<blockquote class="note warn"><strong class="note-title">Path Traversal Vulnerability</strong><p>The built-in Node <code>fs</code> implements <code>contains()</code> with realpath so templates cannot escape the root via symlinks. The browser bundle omits <code>contains</code> (loader treats paths as allowed). For a custom abstract <code>fs</code>, implement <code>contains</code> unless every resolved path is trusted.</p>
</blockquote>
<h2 id="In-memory-Template" class="article-heading"><a href="#In-memory-Template" class="headerlink" title="In-memory Template"></a>In-memory Template<a class="article-anchor" href="#In-memory-Template" aria-hidden="true"></a></h2><p>To facilitate rendering w/o files, theres a <code>templates</code> option to specify a mapping of filenames and their content. LiquidJS will read templates from the mapping.</p>
<h2 id="In-memory-Template" class="article-heading"><a href="#In-memory-Template" class="headerlink" title="In-memory Template"></a>In-memory Template<a class="article-anchor" href="#In-memory-Template" aria-hidden="true"></a></h2><p>To facilitate rendering without files, theres a <code>templates</code> option to specify a mapping of filenames and their content. LiquidJS will read templates from the mapping.</p>
<pre class="line-numbers language-typescript" data-language="typescript"><code class="language-typescript"><span class="token keyword">const</span> engine <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Liquid</span><span class="token punctuation">(</span><span class="token punctuation">&#123;</span>
templates<span class="token operator">:</span> <span class="token punctuation">&#123;</span>
<span class="token string-property property">'views/entry'</span><span class="token operator">:</span> <span class="token string">'header &#123;% include "../partials/footer" %&#125;'</span><span class="token punctuation">,</span>
@@ -181,7 +182,7 @@ engine<span class="token punctuation">.</span><span class="token function">rende
</div>
<footer class="article-footer">
<time class="article-footer-updated" datetime="2026-06-06T17:38:08.031Z" itemprop="dateModified">Last updated: 2026-06-06</time>
<time class="article-footer-updated" datetime="2026-06-07T16:27:07.442Z" itemprop="dateModified">Last updated: 2026-06-07</time>
<a href="options.html" class="article-footer-prev" title="Options"><i class="icon-chevron-left"></i><span>Prev</span></a><a href="partials-and-layouts.html" class="article-footer-next" title="Includes and Layouts"><span>Next</span><i class="icon-chevron-right"></i></a>
</footer>
</div>
+8 -7
View File
@@ -39,6 +39,7 @@
<script src="https://cdn.cookiehub.eu/c2/e8e44c93.js"></script>
<script type="text/javascript">
document.addEventListener("DOMContentLoaded", function(event) {
if (location.hostname === 'localhost' || location.hostname === '127.0.0.1') return;
var cpm = {};
window.cookiehub.load(cpm);
});
@@ -99,7 +100,7 @@
</header>
<div class="article-content" itemprop="articleBody">
<p>Custom tags can have content template and can be nested. This article describes how to implement custom tags that consists of a <em>begin tag</em>, an <em>end tag</em>, and template content between them.</p>
<p>Custom tags can have content templates and can be nested. This article describes how to implement custom tags that consist of a <em>begin tag</em>, an <em>end tag</em>, and template content between them.</p>
<h2 id="Render-Tag-Content" class="article-heading"><a href="#Render-Tag-Content" class="headerlink" title="Render Tag Content"></a>Render Tag Content<a class="article-anchor" href="#Render-Tag-Content" aria-hidden="true"></a></h2><p>Well start with a simple tag <code>wrap</code> which wraps its content into a <code>&lt;div class=&quot;wrapper&quot;&gt;&lt;/div&gt;</code> element:</p>
<pre class="line-numbers language-liquid" data-language="liquid"><code class="language-liquid"><span class="token liquid language-liquid"><span class="token delimiter punctuation">&#123;%</span> wrap <span class="token delimiter punctuation">%&#125;</span></span>
<span class="token liquid language-liquid"><span class="token delimiter punctuation">&#123;&#123;</span> <span class="token string">"hello world!"</span> <span class="token operator">|</span> <span class="token function filter">capitalize</span> <span class="token delimiter punctuation">&#125;&#125;</span></span>
@@ -110,12 +111,12 @@
Hello world!
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span></span></code></pre>
<p>Firstly, <a href="./register-filters-tags.html">register</a> a tag with name <code>wrap</code> and parse the content into <code>this.tpls</code>. Here in <code>parse(tagToken, remainTokens)</code>,</p>
<p>Firstly, <a href="./register-filters-tags.html">register</a> a tag named <code>wrap</code> and parse the content into <code>this.tpls</code>. Here in <code>parse(tagToken, remainTokens)</code>:</p>
<ul>
<li><code>tagToken</code> is current token <code>{% wrap %}</code>, and</li>
<li><code>remainTokens</code> is an array of all tokens following <code>{% wrap %}</code> until the end of this template file.</li>
</ul>
<p>Basically, what we need to do is take/<code>.shift()</code> enough tags from <code>remainTokens</code> until we got a <code>endwrap</code> token (the name can be arbitrary, but in convention, we need it to be <code>endwrap</code>). And if theres no <code>endwrap</code> until the end of template file, we need to throw an tag-not-closed <code>Error</code>.</p>
<p>Basically, what we need to do is take/<code>.shift()</code> enough tags from <code>remainTokens</code> until we get an <code>endwrap</code> token (the name can be arbitrary, but by convention it should be <code>endwrap</code>). And if theres no <code>endwrap</code> until the end of the template file, we need to throw a tag-not-closed <code>Error</code>.</p>
<pre class="line-numbers language-javascript" data-language="javascript"><code class="language-javascript">engine<span class="token punctuation">.</span><span class="token function">registerTag</span><span class="token punctuation">(</span><span class="token string">'wrap'</span><span class="token punctuation">,</span> <span class="token punctuation">&#123;</span>
<span class="token function">parse</span><span class="token punctuation">(</span><span class="token parameter">tagToken<span class="token punctuation">,</span> remainTokens</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
<span class="token keyword">this</span><span class="token punctuation">.</span>tpls <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>
@@ -142,8 +143,8 @@
<span class="token punctuation">&#125;</span>
<span class="token punctuation">&#125;</span><span class="token punctuation">)</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<p><code>.renderTemplates()</code> can be async, we need <code>yield</code> to wait it complete. More details on async in LiquidJS, please refer to <a href="./sync-and-async.html">Sync and Async</a>. Other parts of <code>render()</code> method is quite straightforward. Heres a JSFiddle version: <a target="_blank" rel="noopener external nofollow noreferrer" href="https://jsfiddle.net/por0zcn1/3/">https://jsfiddle.net/por0zcn1/3/</a></p>
<h2 id="Using-ParseStream" class="article-heading"><a href="#Using-ParseStream" class="headerlink" title="Using ParseStream"></a>Using ParseStream<a class="article-anchor" href="#Using-ParseStream" aria-hidden="true"></a></h2><p>When it comes to complex tags like <a href="../tags/for.html">for</a> and <a href="../tags/if.html">if</a>, the <code>parse()</code> can be very complicated. Theres a <a href="/api/classes/ParseStream.html">ParseStream</a> utility to organize the <code>parse()</code> in event-based style. Following is a re-written <code>parse()</code> using <code>ParseStream</code> and does exactly the same as above example.</p>
<p><code>.renderTemplates()</code> can be async; we need <code>yield</code> to wait for it to complete. For more details on async in LiquidJS, see <a href="./sync-and-async.html">Sync and Async</a>. Other parts of the <code>render()</code> method are quite straightforward. Heres a JSFiddle version: <a target="_blank" rel="noopener external nofollow noreferrer" href="https://jsfiddle.net/por0zcn1/3/">https://jsfiddle.net/por0zcn1/3/</a></p>
<h2 id="Using-ParseStream" class="article-heading"><a href="#Using-ParseStream" class="headerlink" title="Using ParseStream"></a>Using ParseStream<a class="article-anchor" href="#Using-ParseStream" aria-hidden="true"></a></h2><p>When it comes to complex tags like <a href="../tags/for.html">for</a> and <a href="../tags/if.html">if</a>, the <code>parse()</code> can be very complicated. Theres a <a href="/api/classes/ParseStream.html">ParseStream</a> utility to organize the <code>parse()</code> in event-based style. Following is a re-written <code>parse()</code> using <code>ParseStream</code> that does exactly the same as the example above.</p>
<pre class="line-numbers language-javascript" data-language="javascript"><code class="language-javascript"><span class="token function">parse</span><span class="token punctuation">(</span><span class="token parameter">tagToken<span class="token punctuation">,</span> remainTokens</span><span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
<span class="token keyword">this</span><span class="token punctuation">.</span>tpls <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>
<span class="token keyword">this</span><span class="token punctuation">.</span>liquid<span class="token punctuation">.</span>parser<span class="token punctuation">.</span><span class="token function">parseStream</span><span class="token punctuation">(</span>remainTokens<span class="token punctuation">)</span>
@@ -155,7 +156,7 @@
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<p>Heres a JSFiddle version: <a target="_blank" rel="noopener external nofollow noreferrer" href="https://jsfiddle.net/por0zcn1/4/">https://jsfiddle.net/por0zcn1/4/</a>. For simplicity, the following examples are implemented using <code>ParseStream</code>.</p>
<h2 id="Manipulate-the-Context" class="article-heading"><a href="#Manipulate-the-Context" class="headerlink" title="Manipulate the Context"></a>Manipulate the Context<a class="article-anchor" href="#Manipulate-the-Context" aria-hidden="true"></a></h2><p>The <code>wrap</code> tag above doesnt seem to be very useful, without using that tag we can render the content anyway. Now were going to implement a <code>repeat</code> tag to render the content 2 times (we can also add a <a href="./parse-parameters.html">parameter</a> to render arbitrary times).</p>
<h2 id="Manipulate-the-Context" class="article-heading"><a href="#Manipulate-the-Context" class="headerlink" title="Manipulate the Context"></a>Manipulate the Context<a class="article-anchor" href="#Manipulate-the-Context" aria-hidden="true"></a></h2><p>The <code>wrap</code> tag above doesnt seem very useful; even without using that tag, we can render the content anyway. Now were going to implement a <code>repeat</code> tag to render the content 2 times (we can also add a <a href="./parse-parameters.html">parameter</a> to render an arbitrary number of times).</p>
<pre class="line-numbers language-liquid" data-language="liquid"><code class="language-liquid"><span class="token liquid language-liquid"><span class="token delimiter punctuation">&#123;%</span> repeat <span class="token delimiter punctuation">%&#125;</span></span>
<span class="token liquid language-liquid"><span class="token delimiter punctuation">&#123;&#123;</span> repeat<span class="token punctuation">.</span>i <span class="token delimiter punctuation">&#125;&#125;</span></span>. <span class="token liquid language-liquid"><span class="token delimiter punctuation">&#123;&#123;</span> <span class="token string">"hello world!"</span> <span class="token operator">|</span> <span class="token function filter">capitalize</span> <span class="token delimiter punctuation">&#125;&#125;</span></span>
<span class="token liquid language-liquid"><span class="token delimiter punctuation">&#123;%</span> endrepeat <span class="token delimiter punctuation">%&#125;</span></span>`<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span></span></code></pre>
@@ -195,7 +196,7 @@
</div>
<footer class="article-footer">
<time class="article-footer-updated" datetime="2026-06-06T17:38:08.031Z" itemprop="dateModified">Last updated: 2026-06-06</time>
<time class="article-footer-updated" datetime="2026-06-07T16:27:07.442Z" itemprop="dateModified">Last updated: 2026-06-07</time>
<a href="parse-parameters.html" class="article-footer-prev" title="Parse Parameters"><i class="icon-chevron-left"></i><span>Prev</span></a><a href="drops.html" class="article-footer-next" title="Liquid Drops"><span>Next</span><i class="icon-chevron-right"></i></a>
</footer>
</div>
+4 -3
View File
@@ -39,6 +39,7 @@
<script src="https://cdn.cookiehub.eu/c2/e8e44c93.js"></script>
<script type="text/javascript">
document.addEventListener("DOMContentLoaded", function(event) {
if (location.hostname === 'localhost' || location.hostname === '127.0.0.1') return;
var cpm = {};
window.cookiehub.load(cpm);
});
@@ -113,7 +114,7 @@
</ul>
<h2 id="Limit-details" class="article-heading"><a href="#Limit-details" class="headerlink" title="Limit details"></a>Limit details<a class="article-anchor" href="#Limit-details" aria-hidden="true"></a></h2><h3 id="parseLimit" class="article-heading"><a href="#parseLimit" class="headerlink" title="parseLimit"></a>parseLimit<a class="article-anchor" href="#parseLimit" aria-hidden="true"></a></h3><p><a href="/api/interfaces/LiquidOptions.html#parseLimit">parseLimit</a> restricts the size (character length) of templates parsed in each <code>.parse()</code> call, including referenced partials and layouts. Since LiquidJS parses template strings in near O(n) time, limiting total template length is usually sufficient.</p>
<p>A typical PC handles <code>1e8</code> (100M) characters without issues.</p>
<h3 id="renderLimit" class="article-heading"><a href="#renderLimit" class="headerlink" title="renderLimit"></a>renderLimit<a class="article-anchor" href="#renderLimit" aria-hidden="true"></a></h3><p>Restricting template size alone is insufficient because dynamic loops with large counts can occur in render time. <a href="/api/interfaces/LiquidOptions.html#renderLimit">renderLimit</a> mitigates this by limiting the time consumed by each <code>render()</code> call.</p>
<h3 id="renderLimit" class="article-heading"><a href="#renderLimit" class="headerlink" title="renderLimit"></a>renderLimit<a class="article-anchor" href="#renderLimit" aria-hidden="true"></a></h3><p>Restricting template size alone is insufficient because dynamic loops with large counts can occur during rendering. <a href="/api/interfaces/LiquidOptions.html#renderLimit">renderLimit</a> mitigates this by limiting the time consumed by each <code>render()</code> call.</p>
<pre class="line-numbers language-liquid" data-language="liquid"><code class="language-liquid"><span class="token liquid language-liquid"><span class="token delimiter punctuation">&#123;%-</span> <span class="token keyword">for</span> i <span class="token keyword">in</span> <span class="token punctuation">(</span><span class="token number">1</span><span class="token range operator">..</span><span class="token number">10000000</span><span class="token punctuation">)</span> <span class="token delimiter punctuation">-%&#125;</span></span>
order: <span class="token liquid language-liquid"><span class="token delimiter punctuation">&#123;&#123;</span>i<span class="token delimiter punctuation">&#125;&#125;</span></span>
<span class="token liquid language-liquid"><span class="token delimiter punctuation">&#123;%-</span> <span class="token keyword">endfor</span> <span class="token delimiter punctuation">-%&#125;</span></span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span></span></code></pre>
@@ -126,7 +127,7 @@
<li>Not guaranteed counted: arbitrary user object behavior such as custom <code>toValue()</code>/<code>toString()</code> chains, or other host-side code that allocates outside LiquidJS accounting points.</li>
</ul>
<p>In other words, <code>memoryLimit</code> limits what LiquidJS counts, not every byte your process may allocate.</p>
<p>Even with small number of templates and iterations, memory usage can grow exponentially. In the following example, memory doubles with each iteration:</p>
<p>Even with a small number of templates and iterations, memory usage can grow exponentially. In the following example, memory doubles with each iteration:</p>
<pre class="line-numbers language-liquid" data-language="liquid"><code class="language-liquid"><span class="token liquid language-liquid"><span class="token delimiter punctuation">&#123;%</span> <span class="token keyword">assign</span> array <span class="token operator">=</span> <span class="token string">"1,2,3"</span> <span class="token operator">|</span> <span class="token function filter">split</span><span class="token operator">:</span> <span class="token string">","</span> <span class="token delimiter punctuation">%&#125;</span></span>
<span class="token liquid language-liquid"><span class="token delimiter punctuation">&#123;%</span> <span class="token keyword">for</span> i <span class="token keyword">in</span> <span class="token punctuation">(</span><span class="token number">1</span><span class="token range operator">..</span><span class="token number">32</span><span class="token punctuation">)</span> <span class="token delimiter punctuation">%&#125;</span></span>
<span class="token liquid language-liquid"><span class="token delimiter punctuation">&#123;%</span> <span class="token keyword">assign</span> array <span class="token operator">=</span> array <span class="token operator">|</span> <span class="token function filter">concat</span><span class="token operator">:</span> array <span class="token delimiter punctuation">%&#125;</span></span>
@@ -145,7 +146,7 @@
</div>
<footer class="article-footer">
<time class="article-footer-updated" datetime="2026-06-06T17:38:08.031Z" itemprop="dateModified">Last updated: 2026-06-06</time>
<time class="article-footer-updated" datetime="2026-06-07T16:27:07.442Z" itemprop="dateModified">Last updated: 2026-06-07</time>
<a href="truthy-and-falsy.html" class="article-footer-prev" title="Truthy and Falsy"><i class="icon-chevron-left"></i><span>Prev</span></a><a href="static-analysis.html" class="article-footer-next" title="Static Analysis"><span>Next</span><i class="icon-chevron-right"></i></a>
</footer>
</div>
+11 -10
View File
@@ -39,6 +39,7 @@
<script src="https://cdn.cookiehub.eu/c2/e8e44c93.js"></script>
<script type="text/javascript">
document.addEventListener("DOMContentLoaded", function(event) {
if (location.hostname === 'localhost' || location.hostname === '127.0.0.1') return;
var cpm = {};
window.cookiehub.load(cpm);
});
@@ -130,39 +131,39 @@ engine
<span class="token comment">&lt;!--for development--></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://cdn.jsdelivr.net/npm/liquidjs/dist/liquid.browser.umd.js<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token script"></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">></span></span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span></span></code></pre>
<blockquote class="note info"><strong class="note-title">Working Demo</strong><p>Heres a living demo on jsFiddle: <a href="https://jsfiddle.net/pd4jhzLs/1/" rel="external nofollow noreferrer" target="_blank">jsfiddle.net/pd4jhzLs/1/</a>, and the source code is also available in <a href="https://github.com/harttle/liquidjs/blob/master/demo/browser/" rel="external nofollow noreferrer" target="_blank">liquidjs/demo/browser/</a>.</p>
<blockquote class="note info"><strong class="note-title">Working Demo</strong><p>Heres a live demo on jsFiddle: <a href="https://jsfiddle.net/pd4jhzLs/1/" rel="external nofollow noreferrer" target="_blank">jsfiddle.net/pd4jhzLs/1/</a>, and the source code is also available in <a href="https://github.com/harttle/liquidjs/blob/master/demo/browser/" rel="external nofollow noreferrer" target="_blank">liquidjs/demo/browser/</a>.</p>
</blockquote>
<blockquote class="note warn"><strong class="note-title">Compatibility</strong><p>You may need a <a href="https://github.com/taylorhakes/promise-polyfill" rel="external nofollow noreferrer" target="_blank">Promise polyfill</a> for legacy browsers like IE and Android UC, see <a href="https://caniuse.com/#feat=promises" rel="external nofollow noreferrer" target="_blank">caniuse statistics</a>. </p>
</blockquote>
<h2 id="LiquidJS-in-CLI" class="article-heading"><a href="#LiquidJS-in-CLI" class="headerlink" title="LiquidJS in CLI"></a>LiquidJS in CLI<a class="article-anchor" href="#LiquidJS-in-CLI" aria-hidden="true"></a></h2><p>LiquidJS can also be used to render a template directly from CLI using <code>npx</code>:</p>
<pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">npx liquidjs <span class="token parameter variable">--template</span> <span class="token string">'&#123;&#123;"hello" | capitalize&#125;&#125;'</span><span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre>
<pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token cli-command builtin class-name">npx</span> liquidjs <span class="token parameter variable">--template</span> <span class="token string">'&#123;&#123;"hello" | capitalize&#125;&#125;'</span><span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre>
<p>You can either pass the template inline (as shown above) or you can read it from a file by using the <code>@</code> character followed by a path, like so:</p>
<pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">npx liquidjs <span class="token parameter variable">--template</span> @./some-template.liquid<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre>
<pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token cli-command builtin class-name">npx</span> liquidjs <span class="token parameter variable">--template</span> @./some-template.liquid<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre>
<p>You can also use the <code>@-</code> syntax to read the template from <code>stdin</code>:</p>
<pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token builtin class-name">echo</span> <span class="token string">'&#123;&#123;"hello" | capitalize&#125;&#125;'</span> <span class="token operator">|</span> npx liquidjs <span class="token parameter variable">--template</span> @-<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre>
<pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token builtin class-name">echo</span> <span class="token string">'&#123;&#123;"hello" | capitalize&#125;&#125;'</span> <span class="token operator">|</span> <span class="token cli-command builtin class-name">npx</span> liquidjs <span class="token parameter variable">--template</span> @-<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre>
<p>A context can be passed in the same ways (i.e. inline, from a path or piped through <code>stdin</code>). The following three are equivalent:</p>
<pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">npx liquidjs <span class="token parameter variable">--template</span> <span class="token string">'Hello, &#123;&#123; name &#125;&#125;!'</span> <span class="token parameter variable">--context</span> <span class="token string">'&#123;"name": "Snake"&#125;'</span>
npx liquidjs <span class="token parameter variable">--template</span> <span class="token string">'Hello, &#123;&#123; name &#125;&#125;!'</span> <span class="token parameter variable">--context</span> @./some-context.json
<span class="token builtin class-name">echo</span> <span class="token string">'&#123;"name": "Snake"&#125;'</span> <span class="token operator">|</span> npx liquidjs <span class="token parameter variable">--template</span> <span class="token string">'Hello, &#123;&#123; name &#125;&#125;!'</span> <span class="token parameter variable">--context</span> @-<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span></span></code></pre>
<pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token cli-command builtin class-name">npx</span> liquidjs <span class="token parameter variable">--template</span> <span class="token string">'Hello, &#123;&#123; name &#125;&#125;!'</span> <span class="token parameter variable">--context</span> <span class="token string">'&#123;"name": "Snake"&#125;'</span>
<span class="token cli-command builtin class-name">npx</span> liquidjs <span class="token parameter variable">--template</span> <span class="token string">'Hello, &#123;&#123; name &#125;&#125;!'</span> <span class="token parameter variable">--context</span> @./some-context.json
<span class="token builtin class-name">echo</span> <span class="token string">'&#123;"name": "Snake"&#125;'</span> <span class="token operator">|</span> <span class="token cli-command builtin class-name">npx</span> liquidjs <span class="token parameter variable">--template</span> <span class="token string">'Hello, &#123;&#123; name &#125;&#125;!'</span> <span class="token parameter variable">--context</span> @-<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span></span></code></pre>
<p>Note that you can only use the <code>stdin</code> specifier <code>@-</code> for a single argument. If you try to use it for both <code>--template</code> and <code>--context</code> you will get an error.</p>
<p>The rendered output is written to <code>stdout</code> by default, but you can also specify an output file (if the file exists, it will be overwritten):</p>
<pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">npx liquidjs <span class="token parameter variable">--template</span> <span class="token string">'&#123;&#123;"hello" | capitalize&#125;&#125;'</span> <span class="token parameter variable">--output</span> ./hello.txt<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre>
<pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token cli-command builtin class-name">npx</span> liquidjs <span class="token parameter variable">--template</span> <span class="token string">'&#123;&#123;"hello" | capitalize&#125;&#125;'</span> <span class="token parameter variable">--output</span> ./hello.txt<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre>
<p>You can also pass a number of options to customize template rendering behavior. For example, the <code>--js-truthy</code> option can be used to enable JavaScript truthiness:</p>
<pre class="line-numbers language-bash" data-language="bash"><code class="language-bash">npx liquidjs <span class="token parameter variable">--template</span> @./some-template.liquid --js-truthy<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre>
<pre class="line-numbers language-bash" data-language="bash"><code class="language-bash"><span class="token cli-command builtin class-name">npx</span> liquidjs <span class="token parameter variable">--template</span> @./some-template.liquid --js-truthy<span aria-hidden="true" class="line-numbers-rows"><span></span></span></code></pre>
<p>Most of the <a href="./options.html">options available through the JavaScript API</a> are also available from the CLI. For help on available options, use <code>npx liquidjs --help</code>.</p>
<h2 id="Miscellaneous" class="article-heading"><a href="#Miscellaneous" class="headerlink" title="Miscellaneous"></a>Miscellaneous<a class="article-anchor" href="#Miscellaneous" aria-hidden="true"></a></h2><p>A ReactJS demo is also added by <a target="_blank" rel="noopener external nofollow noreferrer" href="https://github.com/stevenanthonyrevo">@stevenanthonyrevo</a>, see <a target="_blank" rel="noopener external nofollow noreferrer" href="https://github.com/harttle/liquidjs/blob/master/demo/reactjs/">liquidjs/demo/reactjs/</a>.</p>
</div>
<footer class="article-footer">
<time class="article-footer-updated" datetime="2026-06-06T17:38:08.031Z" itemprop="dateModified">Last updated: 2026-06-06</time>
<time class="article-footer-updated" datetime="2026-06-07T16:27:07.442Z" itemprop="dateModified">Last updated: 2026-06-07</time>
<a href="intro-to-liquid.html" class="article-footer-prev" title="Intro to Liquid"><i class="icon-chevron-left"></i><span>Prev</span></a><a href="options.html" class="article-footer-next" title="Options"><span>Next</span><i class="icon-chevron-right"></i></a>
</footer>
</div>
+4 -3
View File
@@ -39,6 +39,7 @@
<script src="https://cdn.cookiehub.eu/c2/e8e44c93.js"></script>
<script type="text/javascript">
document.addEventListener("DOMContentLoaded", function(event) {
if (location.hostname === 'localhost' || location.hostname === '127.0.0.1') return;
var cpm = {};
window.cookiehub.load(cpm);
});
@@ -101,7 +102,7 @@
<div class="article-content" itemprop="articleBody">
<p class="since">v10.20.0</p>
<blockquote class="note warn"><strong class="note-title">Experimental</strong><p>Note that this is an experimental feature and future APIs are subject to change. And internal structures returned can be changed w/o a major version bump.</p>
<blockquote class="note warn"><strong class="note-title">Experimental</strong><p>Note that this is an experimental feature and future APIs are subject to change. Internal structures returned can be changed without a major version bump.</p>
</blockquote>
<blockquote class="note info"><strong class="note-title">Sync and Async</strong><p>There are synchronous and asynchronous versions of each of the methods demonstrated on this page. See the [Liquid API][liquid-api] for a complete reference.</p>
@@ -278,7 +279,7 @@ engine<span class="token punctuation">.</span><span class="token function">globa
<span class="token punctuation">&#125;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<h3 id="Analyzing-Custom-Tags" class="article-heading"><a href="#Analyzing-Custom-Tags" class="headerlink" title="Analyzing Custom Tags"></a>Analyzing Custom Tags<a class="article-anchor" href="#Analyzing-Custom-Tags" aria-hidden="true"></a></h3><p>For static analysis to include results from custom tags, those tags must implement some additional methods defined on the <a href="/api/interfaces/Template.html">Template interface</a>. LiquidJS will use the information returned from these methods to traverse the template and report variable usage.</p>
<p>Not all methods are required, depending in the kind of tag. If its a block with a start tag, end tag and any amount of Liquid markup in between, it will need to implement the <a href="/api/interfaces/Template.html#children"><code>children()</code></a> method. <code>children()</code> is defined as a generator, so that we can use it in synchronous and asynchronous contexts, just like <code>render()</code>. It should return HTML content, output statements and tags that are child nodes of the current tag.</p>
<p>Not all methods are required, depending on the kind of tag. If its a block with a start tag, end tag and any amount of Liquid markup in between, it will need to implement the <a href="/api/interfaces/Template.html#children"><code>children()</code></a> method. <code>children()</code> is defined as a generator, so that we can use it in synchronous and asynchronous contexts, just like <code>render()</code>. It should return HTML content, output statements and tags that are child nodes of the current tag.</p>
<p>The <a href="/api/interfaces/Template.html#blockScope"><code>blockScope()</code></a> method is responsible for telling LiquidJS which names will be in scope for the duration of the tags block. Some of these names could depend on the tags arguments, and some will be fixed, like <code>forloop</code> from the <code>&#123;% for %&#125;</code> tag.</p>
<p>Whether a tag is an inline tag or a block tag, if it accepts arguments it should implement <a href="/api/interfaces/Template.html#arguments"><code>arguments()</code></a>, which is responsible for returning the tags arguments as a sequence of <a href="/api/classes/Value.html"><code>Value</code></a> instances or tokens of type <a href="/api/types/ValueToken.html"><code>ValueToken</code></a>.</p>
<p>This example demonstrates these methods for a block tag. See LiquidJSs <a target="_blank" rel="noopener external nofollow noreferrer" href="https://github.com/harttle/liquidjs/tree/master/src/tags">built-in tags</a> for more examples.</p>
@@ -324,7 +325,7 @@ engine<span class="token punctuation">.</span><span class="token function">globa
</div>
<footer class="article-footer">
<time class="article-footer-updated" datetime="2026-06-06T17:38:08.031Z" itemprop="dateModified">Last updated: 2026-06-06</time>
<time class="article-footer-updated" datetime="2026-06-07T16:27:07.442Z" itemprop="dateModified">Last updated: 2026-06-07</time>
<a href="security-model.html" class="article-footer-prev" title="Security Model"><i class="icon-chevron-left"></i><span>Prev</span></a><a href="migrate-to-9.html" class="article-footer-next" title="Migrate to LiquidJS 9"><span>Next</span><i class="icon-chevron-right"></i></a>
</footer>
</div>
+7 -6
View File
@@ -39,6 +39,7 @@
<script src="https://cdn.cookiehub.eu/c2/e8e44c93.js"></script>
<script type="text/javascript">
document.addEventListener("DOMContentLoaded", function(event) {
if (location.hostname === 'localhost' || location.hostname === '127.0.0.1') return;
var cpm = {};
window.cookiehub.load(cpm);
});
@@ -99,8 +100,8 @@
</header>
<div class="article-content" itemprop="articleBody">
<p>LiquidJS supports both sync and async evaluate, and can be used with Promises. To reuse the same set of tag/filter implementations in both sync and async, LiquidJS tags are implemented as generators.</p>
<h2 id="Sync-and-Async-API" class="article-heading"><a href="#Sync-and-Async-API" class="headerlink" title="Sync and Async API"></a>Sync and Async API<a class="article-anchor" href="#Sync-and-Async-API" aria-hidden="true"></a></h2><p>All major methods on <a href="/api/classes/Liquid.html">Liquid</a> supports both sync and async. These methods return Promises:</p>
<p>LiquidJS supports both synchronous and asynchronous evaluation, and can be used with Promises. To reuse the same set of tag/filter implementations in both sync and async modes, LiquidJS tags are implemented as generators.</p>
<h2 id="Sync-and-Async-API" class="article-heading"><a href="#Sync-and-Async-API" class="headerlink" title="Sync and Async API"></a>Sync and Async API<a class="article-anchor" href="#Sync-and-Async-API" aria-hidden="true"></a></h2><p>All major methods on <a href="/api/classes/Liquid.html">Liquid</a> support both sync and async. These methods return Promises:</p>
<ul>
<li><code>render()</code></li>
<li><code>renderFile()</code></li>
@@ -133,11 +134,11 @@ engine<span class="token punctuation">.</span><span class="token function">regis
<span class="token punctuation">&#125;</span>
<span class="token punctuation">&#125;</span><span class="token punctuation">)</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<p>All builtin tags are implemented this way and safe to use in both sync and async (Ill call it <em>sync-compatible</em>). To make your custom tag <em>sync-compatible</em>, youll need to:</p>
<p>All built-in tags are implemented this way and are safe to use in both sync and async modes (Ill call it <em>sync-compatible</em>). To make your custom tag <em>sync-compatible</em>, youll need to:</p>
<ul>
<li>declare render function as <code>* render()</code>, in which</li>
<li>do not directly <code>return &lt;Promise&gt;</code>, and</li>
<li>do not call any APIs that returns a Promise.</li>
<li>do not call any APIs that return a Promise.</li>
</ul>
<h2 id="Call-APIs-that-return-a-Promise" class="article-heading"><a href="#Call-APIs-that-return-a-Promise" class="headerlink" title="Call APIs that return a Promise"></a>Call APIs that return a Promise<a class="article-anchor" href="#Call-APIs-that-return-a-Promise" aria-hidden="true"></a></h2><p>But LiquidJS is Promise-friendly, right? You can still call Promise-based functions and wait for that Promise within tag implementations. Just replace <code>await</code> with <code>yield</code>. e.g. were calling <code>fs.readFile()</code> which returns a <code>Promise</code>:</p>
<pre class="line-numbers language-typescript" data-language="typescript"><code class="language-typescript"><span class="token operator">*</span> <span class="token function">render</span> <span class="token punctuation">(</span>ctx<span class="token operator">:</span> Context<span class="token punctuation">,</span> emitter<span class="token operator">:</span> Emitter<span class="token punctuation">)</span> <span class="token punctuation">&#123;</span>
@@ -167,7 +168,7 @@ engine<span class="token punctuation">.</span><span class="token function">regis
<span class="token punctuation">&#125;</span>
<span class="token punctuation">&#125;</span><span class="token punctuation">)</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<h2 id="Async-only-Tags" class="article-heading"><a href="#Async-only-Tags" class="headerlink" title="Async only Tags"></a>Async only Tags<a class="article-anchor" href="#Async-only-Tags" aria-hidden="true"></a></h2><p>If your tag is intend to be used only asynchronously, it can be declared as <code>async render()</code> so you can use <code>await</code> in its implementation directly:</p>
<h2 id="Async-only-Tags" class="article-heading"><a href="#Async-only-Tags" class="headerlink" title="Async only Tags"></a>Async only Tags<a class="article-anchor" href="#Async-only-Tags" aria-hidden="true"></a></h2><p>If your tag is intended to be used only asynchronously, it can be declared as <code>async render()</code> so you can use <code>await</code> in its implementation directly:</p>
<pre class="line-numbers language-typescript" data-language="typescript"><code class="language-typescript"><span class="token keyword">import</span> <span class="token punctuation">&#123;</span> toPromise<span class="token punctuation">,</span> TagToken<span class="token punctuation">,</span> Context<span class="token punctuation">,</span> Emitter<span class="token punctuation">,</span> TopLevelToken<span class="token punctuation">,</span> Value<span class="token punctuation">,</span> Tag<span class="token punctuation">,</span> Liquid <span class="token punctuation">&#125;</span> <span class="token keyword">from</span> <span class="token string">'liquidjs'</span>
<span class="token comment">// Usage: &#123;% upper "alice" %&#125;</span>
@@ -187,7 +188,7 @@ engine<span class="token punctuation">.</span><span class="token function">regis
</div>
<footer class="article-footer">
<time class="article-footer-updated" datetime="2026-06-06T17:38:08.031Z" itemprop="dateModified">Last updated: 2026-06-06</time>
<time class="article-footer-updated" datetime="2026-06-07T16:27:07.442Z" itemprop="dateModified">Last updated: 2026-06-07</time>
<a href="drops.html" class="article-footer-prev" title="Liquid Drops"><i class="icon-chevron-left"></i><span>Prev</span></a><a href="whitespace-control.html" class="article-footer-next" title="Whitespace Control"><span>Next</span><i class="icon-chevron-right"></i></a>
</footer>
</div>
+4 -3
View File
@@ -39,6 +39,7 @@
<script src="https://cdn.cookiehub.eu/c2/e8e44c93.js"></script>
<script type="text/javascript">
document.addEventListener("DOMContentLoaded", function(event) {
if (location.hostname === 'localhost' || location.hostname === '127.0.0.1') return;
var cpm = {};
window.cookiehub.load(cpm);
});
@@ -99,7 +100,7 @@
</header>
<div class="article-content" itemprop="articleBody">
<p>Though <a target="_blank" rel="noopener external nofollow noreferrer" href="https://www.npmjs.com/package/liquidjs">Liquid</a> is platform-independent, therere <a target="_blank" rel="noopener external nofollow noreferrer" href="https://github.com/harttle/liquidjs#differences-and-limitations">certain differences</a> with <a target="_blank" rel="noopener external nofollow noreferrer" href="https://shopify.github.io/liquid">the Ruby version</a>, one of which is the <code>truthy</code> value.</p>
<p>Though <a target="_blank" rel="noopener external nofollow noreferrer" href="https://www.npmjs.com/package/liquidjs">Liquid</a> is platform-independent, there are <a target="_blank" rel="noopener external nofollow noreferrer" href="https://github.com/harttle/liquidjs#differences-and-limitations">certain differences</a> with <a target="_blank" rel="noopener external nofollow noreferrer" href="https://shopify.github.io/liquid">the Ruby version</a>, one of which is the <code>truthy</code> value.</p>
<h2 id="The-Truth-Table" class="article-heading"><a href="#The-Truth-Table" class="headerlink" title="The Truth Table"></a>The Truth Table<a class="article-anchor" href="#The-Truth-Table" aria-hidden="true"></a></h2><p>According to <a target="_blank" rel="noopener external nofollow noreferrer" href="https://shopify.github.io/liquid/basics/truthy-and-falsy/">Shopify document</a> everything other than <code>false</code> and <code>nil</code> is truthy. But in JavaScript we have a totally different type system, we have types like <code>undefined</code> and we dont differentiate <code>integer</code> and <code>float</code>, thus things are slightly different:</p>
<table>
<thead>
@@ -165,7 +166,7 @@
<td></td>
</tr>
</tbody></table>
<h2 id="Use-JavaScript-Truthy" class="article-heading"><a href="#Use-JavaScript-Truthy" class="headerlink" title="Use JavaScript Truthy"></a>Use JavaScript Truthy<a class="article-anchor" href="#Use-JavaScript-Truthy" aria-hidden="true"></a></h2><p>Note that liquidjs use Shopifys truthiness by default. But it can be toggled to used standard JavaScript truthiness by setting the <strong>jsTruthy</strong> option to <code>true</code>.</p>
<h2 id="Use-JavaScript-Truthy" class="article-heading"><a href="#Use-JavaScript-Truthy" class="headerlink" title="Use JavaScript Truthy"></a>Use JavaScript Truthy<a class="article-anchor" href="#Use-JavaScript-Truthy" aria-hidden="true"></a></h2><p>Note that LiquidJS uses Shopifys truthiness by default. It can be toggled to use standard JavaScript truthiness by setting the <strong>jsTruthy</strong> option to <code>true</code>.</p>
<table>
<thead>
<tr>
@@ -233,7 +234,7 @@
</div>
<footer class="article-footer">
<time class="article-footer-updated" datetime="2026-06-06T17:38:08.031Z" itemprop="dateModified">Last updated: 2026-06-06</time>
<time class="article-footer-updated" datetime="2026-06-07T16:27:07.442Z" itemprop="dateModified">Last updated: 2026-06-07</time>
<a href="operators.html" class="article-footer-prev" title="Operators"><i class="icon-chevron-left"></i><span>Prev</span></a><a href="security-model.html" class="article-footer-next" title="Security Model"><span>Next</span><i class="icon-chevron-right"></i></a>
</footer>
</div>
+4 -3
View File
@@ -39,6 +39,7 @@
<script src="https://cdn.cookiehub.eu/c2/e8e44c93.js"></script>
<script type="text/javascript">
document.addEventListener("DOMContentLoaded", function(event) {
if (location.hostname === 'localhost' || location.hostname === '127.0.0.1') return;
var cpm = {};
window.cookiehub.load(cpm);
});
@@ -99,7 +100,7 @@
</header>
<div class="article-content" itemprop="articleBody">
<p>LiquidJS is compatible to the <a target="_blank" rel="noopener external nofollow noreferrer" href="https://expressjs.com/en/resources/template-engines.html">express template engines</a>. You can set liquidjs instance to the <a target="_blank" rel="noopener external nofollow noreferrer" href="https://expressjs.com/en/guide/using-template-engines.html">view engine</a> option:</p>
<p>LiquidJS is compatible with <a target="_blank" rel="noopener external nofollow noreferrer" href="https://expressjs.com/en/resources/template-engines.html">Express template engines</a>. You can set the LiquidJS instance as the <a target="_blank" rel="noopener external nofollow noreferrer" href="https://expressjs.com/en/guide/using-template-engines.html">view engine</a> option:</p>
<pre class="line-numbers language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">var</span> <span class="token punctuation">&#123;</span> Liquid <span class="token punctuation">&#125;</span> <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'liquidjs'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">var</span> engine <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Liquid</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
@@ -132,7 +133,7 @@ app<span class="token punctuation">.</span><span class="token function">set</spa
<pre class="line-numbers language-javascript" data-language="javascript"><code class="language-javascript">res<span class="token punctuation">.</span><span class="token function">render</span><span class="token punctuation">(</span><span class="token string">'hello'</span><span class="token punctuation">)</span>
res<span class="token punctuation">.</span><span class="token function">render</span><span class="token punctuation">(</span><span class="token string">'world'</span><span class="token punctuation">)</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre>
<h2 id="Caching" class="article-heading"><a href="#Caching" class="headerlink" title="Caching"></a>Caching<a class="article-anchor" href="#Caching" aria-hidden="true"></a></h2><p>Simply setting the <a href="/api/interfaces/LiquidOptions.html#cache">cache option</a> to true will enable template caching, as explained in <a href="./caching.html">Caching</a>. Its recommended to enable cache in production environment, which can be done by:</p>
<h2 id="Caching" class="article-heading"><a href="#Caching" class="headerlink" title="Caching"></a>Caching<a class="article-anchor" href="#Caching" aria-hidden="true"></a></h2><p>Simply setting the <a href="/api/interfaces/LiquidOptions.html#cache">cache option</a> to true will enable template caching, as explained in <a href="./caching.html">Caching</a>. Its recommended to enable cache in a production environment, which can be done by:</p>
<pre class="line-numbers language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">var</span> <span class="token punctuation">&#123;</span> Liquid <span class="token punctuation">&#125;</span> <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'liquidjs'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">var</span> engine <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Liquid</span><span class="token punctuation">(</span><span class="token punctuation">&#123;</span>
<span class="token literal-property property">cache</span><span class="token operator">:</span> process<span class="token punctuation">.</span>env<span class="token punctuation">.</span><span class="token constant">NODE_ENV</span> <span class="token operator">===</span> <span class="token string">'production'</span>
@@ -141,7 +142,7 @@ res<span class="token punctuation">.</span><span class="token function">render</
</div>
<footer class="article-footer">
<time class="article-footer-updated" datetime="2026-06-06T17:38:08.031Z" itemprop="dateModified">Last updated: 2026-06-06</time>
<time class="article-footer-updated" datetime="2026-06-07T16:27:07.442Z" itemprop="dateModified">Last updated: 2026-06-07</time>
<a href="partials-and-layouts.html" class="article-footer-prev" title="Includes and Layouts"><i class="icon-chevron-left"></i><span>Prev</span></a><a href="caching.html" class="article-footer-next" title="Caching"><span>Next</span><i class="icon-chevron-right"></i></a>
</footer>
</div>
+4 -3
View File
@@ -39,6 +39,7 @@
<script src="https://cdn.cookiehub.eu/c2/e8e44c93.js"></script>
<script type="text/javascript">
document.addEventListener("DOMContentLoaded", function(event) {
if (location.hostname === 'localhost' || location.hostname === '127.0.0.1') return;
var cpm = {};
window.cookiehub.load(cpm);
});
@@ -104,11 +105,11 @@
<pre class="line-numbers language-liquid" data-language="liquid"><code class="language-liquid"><span class="token liquid language-liquid"><span class="token delimiter punctuation">&#123;%</span> author <span class="token operator">=</span> <span class="token string">"harttle"</span> <span class="token delimiter punctuation">%&#125;</span></span>
<span class="token liquid language-liquid"><span class="token delimiter punctuation">&#123;&#123;</span> author <span class="token delimiter punctuation">&#125;&#125;</span></span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre>
<p>Outputs (note the blank link):</p>
<p>Outputs (note the blank line):</p>
<pre class="line-numbers language-none"><code class="language-none">
harttle<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre>
<p>We can include hyphens in your tag syntax (<code>{{-</code>, <code>-&#125;&#125;</code>, <code>{%-</code>, <code>-%&#125;</code>) to strip whitespace from left or right. For example:</p>
<p>You can include hyphens in tag syntax (<code>{{-</code>, <code>-&#125;&#125;</code>, <code>{%-</code>, <code>-%&#125;</code>) to strip whitespace from the left or right. For example:</p>
<pre class="line-numbers language-liquid" data-language="liquid"><code class="language-liquid"><span class="token liquid language-liquid"><span class="token delimiter punctuation">&#123;%</span> <span class="token keyword">assign</span> author <span class="token operator">=</span> <span class="token string">"harttle"</span> <span class="token delimiter punctuation">-%&#125;</span></span>
<span class="token liquid language-liquid"><span class="token delimiter punctuation">&#123;&#123;</span> author <span class="token delimiter punctuation">&#125;&#125;</span></span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre>
@@ -128,7 +129,7 @@ harttle<span aria-hidden="true" class="line-numbers-rows"><span></span><span></s
</div>
<footer class="article-footer">
<time class="article-footer-updated" datetime="2026-06-06T17:38:08.031Z" itemprop="dateModified">Last updated: 2026-06-06</time>
<time class="article-footer-updated" datetime="2026-06-07T16:27:07.442Z" itemprop="dateModified">Last updated: 2026-06-07</time>
<a href="sync-and-async.html" class="article-footer-prev" title="Sync and Async"><i class="icon-chevron-left"></i><span>Prev</span></a><a href="plugins.html" class="article-footer-next" title="Plugins"><span>Next</span><i class="icon-chevron-right"></i></a>
</footer>
</div>