Nibbling Perfect Macaroni

    TypeScript icon, indicating that this package has built-in type declarations

    0.1.4 • Public • Published



    This originated as a typescriptification of harttle/liquidjs, itself based on liquid-node and huge thanks are offered breaking the back of implementing liquid in javascript. As I started work, it was obvious that it wasn't going to remain analogous with the original project, and hence making this a hard fork

    The original work, of course, comes from shopify/liquid - and thanks to them for such a great platform to work from.


    npm install --save liquidts


    • Performance with large numbers of blocks needs to be investigated, especially in loop situations


    By default, liquidts won't attempt to load any files for Engine#renderFile or {% include %} tags. If you want to use file loading, then you can either use the provided file-system based engine, or implement your own.


    Performance with strings in Node is atrocious, so we try and avoid manipulating them wherever possible. There is a naive implementation of a "write buffer" in this library that concatenates all writes into an array and then joins it when the consumer reads it. This is a lot faster than working on a "state" string, but still could be better. The options object that .render accepts as its third argument allows you to pass a writer: Writeable in to allow you to implement this yourself.

    Render from String

    Parse and Render:

    const Liquid = require('liquidts');
    const engine = Liquid();
    engine.parseAndRender('{{name | capitalize}}', {name: 'alice'})
        .then(output => {
            // === 'Alice'

    Caching templates:

    const tpl = engine.parse('{{name | capitalize}}');
    engine.render(tpl, {name: 'alice'})
        .then(output => {
            // === 'Alice'


    The full list of options for Liquid() is listed as following:

    • fileSystem needs to be an object implementing FileSystem if you wish to render files rather than ad-hoc strings, or to use include tags

    • registers are a globally available Map of settings and the like that can be consumed by tags but not templates

    • strictFilters is used to enable strict filter existence. If set to false, undefined filters will be rendered as empty string. Otherwise, undefined filters will cause an exception. Defaults to false.

    • strictVariables is used to enable strict variable derivation. If set to false, undefined variables will be rendered as empty string. Otherwise, undefined variables will cause an exception. Defaults to false.

    • trimRight is used to strip blank characters (including , \t, and \r) from the right of tags ({% %}) until \n (inclusive). Defaults to false.

    • trimLeft is similiar to trimRight, whereas the \n is exclusive. Defaults to false.

    • greedy is used to specify whether trimLeft/trimRight is greedy. When set to true, all successive blank characters including \n will be trimed regardless of line breaks. Defaults to false.


    // file: color.liquid
    color: '{{ color }}' shape: '{{ shape }}'
    // file: theme.liquid
    {% assign shape = 'circle' %}
    {% include 'color' %}
    {% include 'color' with 'red' %}
    {% include 'color', color: 'yellow', shape: 'square' %}

    The output will be:

    color: '' shape: 'circle'
    color: 'red' shape: 'circle'
    color: 'yellow' shape: 'square'


    // file: default-layout.liquid
    {% block content %}My default content{% endblock %}
    // file: page.liquid
    {% layout "default-layout" %}
    {% block content %}My page content{% endblock %}

    The output of page.liquid:

    My page content
    • It's possible to define multiple blocks.
    • block name is optional when there's only one block.

    Register Filters

    // Usage: {{ name | uppper }}
    engine.registerFilter('upper', function(v){
        return v.toUpperCase();

    See existing filter implementations:

    Register Tags

    // Usage: {% upper name%}
    engine.registerTag('upper', {
        parse: function(tagToken, remainTokens) {
            this.str = tagToken.args; // name
        render: function(scope, hash) {
            var str = Liquid.evalValue(this.str, scope); // 'alice'
            return Promise.resolve(str.toUpperCase()); // 'Alice'

    See existing tag implementations:

    Contribution Guide

    1. Write a test to define the feature you want.
    2. File an issue, or optionally:
    3. Get your test pass and make a pull request.


    npm i liquidts

    DownloadsWeekly Downloads






    Last publish


    • musicglue-admin