[FEATURE] render with params + LiquidJS vs Go Liquid comparison
Pre-submission Checklist
- [x] I have searched the issue list for similar feature requests
Problem Description
Hi, thanks for creating this lib.
In my use-case users build templates on the frontend (preview with LiquidJS) and are served by backend Go Liquid. Sadly it does not support yet render with params, and I'd like to know if someone is already working on it please?
Proposed Solution
It should accept syntax:
{% render "snippet.liquid", product: product, color: "blue" %}
Alternatives Considered
LiquidJS embedded in Go v8
Shopify Liquid Compatibility
https://shopify.dev/docs/storefronts/themes/architecture/snippets
Additional Context
FYI here is a full comparison with LiquidJS compatibility:
Liquid Template Engine Comparison
LiquidJS vs Go Liquid (osteele/liquid)
Date: November 18, 2025
LiquidJS Version: Latest (main branch)
Go Liquid Version: Latest (main branch)
Executive Summary
This document provides a comprehensive feature comparison between two popular Liquid template engine implementations:
- LiquidJS (harttle/liquidjs) - JavaScript/TypeScript implementation
- Go Liquid (osteele/liquid) - Go implementation
Quick Feature Parity Overview
| Category | LiquidJS | Go Liquid | Notes |
|---|---|---|---|
| Tags | 21 tags | 12 tags | LiquidJS has 9 more tags |
| Filters | 85+ filters | 45+ filters | LiquidJS has ~40 more filters |
| Operators | Full support | Full support | Both support all standard operators |
| Whitespace Control | ✅ Full support | ✅ Full support | Both use - syntax |
| Dynamic Partials | ✅ Supported | ⚠️ Limited | LiquidJS has more flexibility |
| Extensibility | ✅ Excellent | ✅ Good | Both allow custom filters/tags |
| Performance | Good | Excellent | Go has better raw performance |
| Memory Safety | JavaScript VM | Native Go | Go has stronger memory safety |
Key Differences
- Tag Support: LiquidJS has more advanced tags like
render,layout,block,echo,liquid, andinline-comment - Filter Richness: LiquidJS offers significantly more filters, especially for array manipulation and expressions
- Render Tag: LiquidJS has full
rendertag with variable isolation; Go Liquid only hasinclude - Expression Filters: LiquidJS supports
*_expfilters (where_exp, reject_exp, etc.) for dynamic filtering - Jekyll Compatibility: Both support Jekyll extensions, but with different APIs
1. Tags Comparison
1.1 Control Flow Tags
| Tag | LiquidJS | Go Liquid | Syntax Differences | Behavior Notes |
|---|---|---|---|---|
| if | ✅ Full support | ✅ Full support | Identical | Same behavior |
| unless | ✅ Full support | ✅ Full support | Identical | Same behavior (inverted if) |
| elsif | ✅ Full support | ✅ Full support | Identical | Used within if/unless blocks |
| else | ✅ Full support | ✅ Full support | Identical | Used within if/unless/case blocks |
| case | ✅ Full support | ✅ Full support | Identical | Switch-like conditional |
| when | ✅ Full support | ✅ Full support | Identical | Used within case blocks |
Syntax Example (Identical):
{% if user.age >= 18 %}
Adult
{% elsif user.age >= 13 %}
Teen
{% else %}
Child
{% endif %}
1.2 Iteration Tags
| Tag | LiquidJS | Go Liquid | Syntax Differences | Behavior Notes |
|---|---|---|---|---|
| for | ✅ Full support | ✅ Full support | Identical | Loop over arrays/objects |
| break | ✅ Full support | ✅ Full support | Identical | Exit loop early |
| continue | ✅ Full support | ✅ Full support | Identical | Skip to next iteration |
| cycle | ✅ Full support | ✅ Full support | Identical | Cycle through values |
| tablerow | ✅ Full support | ✅ Full support | Identical | Generate HTML table rows |
For Loop Modifiers:
{% for item in collection limit:5 offset:10 reversed %}
{{ item }}
{% endfor %}
- ✅ Both support:
limit,offset,reversed - ✅ Both provide:
forloop.index,forloop.first,forloop.last, etc.
Else Clause:
{% for item in collection %}
{{ item }}
{% else %}
No items found
{% endfor %}
- ✅ LiquidJS: Fully supported
- ✅ Go Liquid: Fully supported
1.3 Variable Assignment Tags
| Tag | LiquidJS | Go Liquid | Syntax Differences | Behavior Notes |
|---|---|---|---|---|
| assign | ✅ Full support | ✅ Full support | Identical | Create/update variables |
| capture | ✅ Full support | ✅ Full support | Identical | Capture block content as variable |
| increment | ✅ Supported | ❌ Not supported | - | Auto-incrementing counter |
| decrement | ✅ Supported | ❌ Not supported | - | Auto-decrementing counter |
Syntax Examples:
{% assign name = "John" %}
{% capture greeting %}Hello {{ name }}{% endcapture %}
{# LiquidJS only: #}
{% increment my_counter %} {# outputs: 0, then 1, then 2... #}
{% decrement my_counter %} {# outputs: -1, then -2, then -3... #}
Notes:
- Go Liquid:
incrementanddecrementtags are not implemented - Jekyll Extensions: Go Liquid supports dot notation in assign (e.g.,
{% assign obj.prop = value %}) when Jekyll extensions are enabled
1.4 Template Inclusion Tags
| Tag | LiquidJS | Go Liquid | Syntax Differences | Behavior Notes |
|---|---|---|---|---|
| include | ✅ Full support | ✅ Full support | Different scoping | LiquidJS more flexible |
| render | ✅ Full support | ❌ Not supported | - | Variable isolation |
| layout | ✅ Supported | ❌ Not supported | - | Template inheritance |
| block | ✅ Supported | ❌ Not supported | - | Content blocks for layouts |
Include Tag:
LiquidJS:
{% include "header.liquid" %}
{% include "header.liquid" with product %}
{% include "header.liquid" with product as item %}
{% include "header.liquid" for products %}
{% include "header.liquid", color: "blue", size: "large" %}
Go Liquid:
{% include "header.liquid" %}
{# No with/for/as syntax support #}
{# Variables passed via RenderFile context #}
Render Tag (LiquidJS only):
{% render "snippet.liquid", product: product, color: "blue" %}
{# Variables are isolated - parent scope not accessible #}
Layout/Block Tags (LiquidJS only):
{# layout.liquid #}
<html>
<body>
{% block content %}Default content{% endblock %}
</body>
</html>
{# page.liquid #}
{% layout "layout.liquid" %}
{% block content %}Custom content{% endblock %}
Key Differences:
- include in LiquidJS has parent scope access by default
- render in LiquidJS provides isolated scope
- Go Liquid only has include with custom file system interface
1.5 Output and Raw Tags
| Tag | LiquidJS | Go Liquid | Syntax Differences | Behavior Notes |
|---|---|---|---|---|
| echo | ✅ Supported | ❌ Not supported | - | Alternative to {{ }} |
| raw | ✅ Full support | ✅ Full support | Identical | Disable Liquid parsing |
| comment | ✅ Full support | ✅ Full support | Identical | Multi-line comments |
| liquid | ✅ Supported | ❌ Not supported | - | Tag without delimiters |
| # (inline comment) | ✅ Supported | ❌ Not supported | - | Single-line comments |
Syntax Examples:
Echo Tag (LiquidJS only):
{% echo product.title %}
{# Equivalent to: {{ product.title }} #}
Liquid Tag (LiquidJS only):
{% liquid
assign name = "John"
if name == "John"
echo "Hello John"
endif
%}
Inline Comment (LiquidJS only):
{% # This is an inline comment %}
Raw Tag (Both):
{% raw %}
This {{ will not }} be parsed
{% endraw %}
Comment Tag (Both):
{% comment %}
Multi-line comment
that spans several lines
{% endcomment %}
2. Filters Comparison
2.1 String Filters
| Filter | LiquidJS | Go Liquid | Syntax Differences | Behavior Notes |
|---|---|---|---|---|
| append | ✅ | ✅ | Identical | Add string to end |
| prepend | ✅ | ✅ | Identical | Add string to start |
| capitalize | ✅ | ✅ | Identical | Capitalize first letter |
| downcase | ✅ | ✅ | Identical | Convert to lowercase |
| upcase | ✅ | ✅ | Identical | Convert to uppercase |
| strip | ✅ | ✅ | Different | LiquidJS supports char param |
| lstrip | ✅ | ✅ | Different | LiquidJS supports char param |
| rstrip | ✅ | ✅ | Different | LiquidJS supports char param |
| strip_html | ✅ | ✅ | Identical | Remove HTML tags |
| strip_newlines | ✅ | ✅ | Identical | Remove newlines |
| newline_to_br | ✅ | ✅ | Identical | Convert \n to <br /> |
| remove | ✅ | ✅ | Identical | Remove all occurrences |
| remove_first | ✅ | ✅ | Identical | Remove first occurrence |
| remove_last | ✅ | ❌ | - | Remove last occurrence |
| replace | ✅ | ✅ | Identical | Replace all occurrences |
| replace_first | ✅ | ✅ | Identical | Replace first occurrence |
| replace_last | ✅ | ❌ | - | Replace last occurrence |
| split | ✅ | ✅ | Identical | Split string into array |
| slice | ✅ | ✅ | Identical | Extract substring |
| truncate | ✅ | ✅ | Identical | Truncate to length |
| truncatewords | ✅ | ✅ | Identical | Truncate to word count |
| normalize_whitespace | ✅ | ❌ | - | Collapse multiple spaces |
| number_of_words | ✅ | ❌ | - | Count words (CJK support) |
Syntax Examples:
Strip with custom characters (LiquidJS):
{{ "...hello..." | strip: "." }} {# Output: hello #}
Strip (Go Liquid):
{{ " hello " | strip }} {# Output: hello #}
{# No custom character parameter #}
Number of words (LiquidJS only):
{{ "Hello world" | number_of_words }} {# Output: 2 #}
{{ "你好世界" | number_of_words: "cjk" }} {# Output: 4 #}
2.2 Array Filters
| Filter | LiquidJS | Go Liquid | Syntax Differences | Behavior Notes |
|---|---|---|---|---|
| join | ✅ | ✅ | Identical | Join array elements |
| first | ✅ | ✅ | Identical | Get first element |
| last | ✅ | ✅ | Identical | Get last element |
| concat | ✅ | ✅ | Identical | Concatenate arrays |
| map | ✅ | ✅ | Identical | Extract property from each item |
| reverse | ✅ | ✅ | Identical | Reverse array |
| size | ✅ | ✅ | Identical | Get array/string length |
| sort | ✅ | ✅ | Identical | Sort array |
| sort_natural | ✅ | ✅ | Identical | Case-insensitive sort |
| uniq | ✅ | ✅ | Identical | Remove duplicates |
| compact | ✅ | ✅ | Identical | Remove nil values |
| where | ✅ | ❌ | - | Filter by property value |
| where_exp | ✅ | ❌ | - | Filter by expression |
| reject | ✅ | ❌ | - | Inverse of where |
| reject_exp | ✅ | ❌ | - | Inverse of where_exp |
| find | ✅ | ❌ | - | Find first matching item |
| find_exp | ✅ | ❌ | - | Find by expression |
| find_index | ✅ | ❌ | - | Find index of item |
| find_index_exp | ✅ | ❌ | - | Find index by expression |
| has | ✅ | ❌ | - | Check if array has item |
| has_exp | ✅ | ❌ | - | Check by expression |
| group_by | ✅ | ❌ | - | Group by property |
| group_by_exp | ✅ | ❌ | - | Group by expression |
| sum | ✅ | ❌ | - | Sum numeric values |
| push | ✅ | ❌ | - | Add item to end |
| pop | ✅ | ❌ | - | Remove item from end |
| shift | ✅ | ❌ | - | Remove item from start |
| unshift | ✅ | ❌ | - | Add item to start |
| sample | ✅ | ❌ | - | Random sample |
| array_to_sentence_string | ✅ | ❌ | - | Convert to sentence |
Syntax Examples:
Where filter (LiquidJS only):
{{ products | where: "featured", true }}
{{ products | where: "price" }} {# truthy values #}
Expression filters (LiquidJS only):
{{ products | where_exp: "item", "item.price < 100" }}
{{ products | reject_exp: "item", "item.sold_out" }}
{{ products | find_exp: "item", "item.id == 5" }}
Group by (LiquidJS only):
{% assign by_type = products | group_by: "type" %}
{% for group in by_type %}
<h3>{{ group.name }}</h3>
{% for product in group.items %}
{{ product.title }}
{% endfor %}
{% endfor %}
Array manipulation (LiquidJS only):
{{ array | push: "new_item" }}
{{ array | pop }}
{{ array | shift }}
{{ array | unshift: "first_item" }}
{{ array | sample: 3 }} {# Random 3 items #}
2.3 Math Filters
| Filter | LiquidJS | Go Liquid | Syntax Differences | Behavior Notes |
|---|---|---|---|---|
| abs | ✅ | ✅ | Identical | Absolute value |
| ceil | ✅ | ✅ | Identical | Round up |
| floor | ✅ | ✅ | Identical | Round down |
| round | ✅ | ✅ | Identical | Round to precision |
| plus | ✅ | ✅ | Different | Go has type-aware arithmetic |
| minus | ✅ | ✅ | Different | Go has type-aware arithmetic |
| times | ✅ | ✅ | Different | Go has type-aware arithmetic |
| divided_by | ✅ | ✅ | Different | Go supports integer division |
| modulo | ✅ | ✅ | Identical | Remainder operation |
| at_least | ✅ | ❌ | - | Return value or minimum |
| at_most | ✅ | ❌ | - | Return value or maximum |
Syntax Examples:
Divided by with integer arithmetic (LiquidJS):
{{ 10 | divided_by: 3 }} {# Output: 3.33... #}
{{ 10 | divided_by: 3, true }} {# Output: 3 (integer) #}
At least/most (LiquidJS only):
{{ 5 | at_least: 10 }} {# Output: 10 #}
{{ 15 | at_most: 10 }} {# Output: 10 #}
Go Liquid Type-Aware Arithmetic:
- When both operands are integers, returns integer
- When either operand is float, returns float
- Division by zero returns error
2.4 Date Filters
| Filter | LiquidJS | Go Liquid | Syntax Differences | Behavior Notes |
|---|---|---|---|---|
| date | ✅ Full support | ✅ Full support | Different | LiquidJS has more format codes |
| date_to_xmlschema | ✅ | ❌ | - | ISO 8601 format |
| date_to_rfc822 | ✅ | ❌ | - | RFC 822 format |
| date_to_string | ✅ | ❌ | - | Short date format |
| date_to_long_string | ✅ | ❌ | - | Long date format |
Syntax Examples:
Date filter:
{# Both: #}
{{ "now" | date: "%Y-%m-%d" }}
{# LiquidJS only: #}
{{ "now" | date: "%Y-%m-%d", 480 }} {# timezone offset #}
{{ date | date_to_xmlschema }} {# 2025-11-18T10:30:00+00:00 #}
{{ date | date_to_rfc822 }} {# Mon, 18 Nov 2025 10:30:00 +0000 #}
Go Liquid:
- Uses
github.com/osteele/tuesdayfor strftime - Supports standard strftime format codes
- Takes
time.Timeas input
LiquidJS:
- Parses strings like "now", "today", or timestamps
- Supports timezone offset parameter
- More specialized date formatting filters
2.5 HTML/URL Filters
| Filter | LiquidJS | Go Liquid | Syntax Differences | Behavior Notes |
|---|---|---|---|---|
| escape | ✅ | ✅ | Identical | HTML escape |
| escape_once | ✅ | ✅ | Identical | Escape unescaped only |
| xml_escape | ✅ | ❌ | - | Alias for escape |
| url_encode | ✅ | ✅ | Identical | URL encode |
| url_decode | ✅ | ✅ | Identical | URL decode |
| uri_escape | ✅ | ❌ | - | URI encode (preserves []) |
| cgi_escape | ✅ | ❌ | - | CGI-style encoding |
| slugify | ✅ | ❌ | - | Convert to URL slug |
Syntax Examples:
Slugify (LiquidJS only):
{{ "Hello World!" | slugify }} {# hello-world #}
{{ "Hello World!" | slugify: "ascii" }} {# hello-world #}
{{ "Hello World!" | slugify: "pretty" }} {# hello-world! #}
{{ "Café" | slugify: "latin" }} {# cafe #}
CGI escape (LiquidJS only):
{{ "hello world" | cgi_escape }} {# hello+world #}
{{ "hello world" | url_encode }} {# hello+world (same) #}
{{ "hello world" | uri_escape }} {# hello%20world #}
2.6 Utility Filters
| Filter | LiquidJS | Go Liquid | Syntax Differences | Behavior Notes |
|---|---|---|---|---|
| default | ✅ | ✅ | Different | LiquidJS has allow_false |
| json / jsonify | ✅ | ✅ | Identical | Convert to JSON |
| inspect | ✅ | ✅ | Different | LiquidJS handles circular refs |
| raw | ✅ | ❌ | - | Output without escaping |
| to_integer | ✅ | ❌ | - | Convert to integer |
| type | ❌ | ✅ | - | Get Go type string |
| base64_encode | ✅ | ❌ | - | Base64 encode |
| base64_decode | ✅ | ❌ | - | Base64 decode |
Syntax Examples:
Default with allow_false (LiquidJS):
{{ false | default: "backup" }} {# Output: backup #}
{{ false | default: "backup", allow_false: true }} {# Output: false #}
Base64 (LiquidJS only):
{{ "Hello World" | base64_encode }} {# SGVsbG8gV29ybGQ= #}
{{ "SGVsbG8gV29ybGQ=" | base64_decode }} {# Hello World #}
Type (Go Liquid only):
{{ value | type }} {# Output: string, []interface{}, etc. #}
3. Operators & Expressions
3.1 Comparison Operators
| Operator | LiquidJS | Go Liquid | Notes |
|---|---|---|---|
| == | ✅ | ✅ | Equal |
| != | ✅ | ✅ | Not equal |
| > | ✅ | ✅ | Greater than |
| < | ✅ | ✅ | Less than |
| >= | ✅ | ✅ | Greater than or equal |
| <= | ✅ | ✅ | Less than or equal |
| contains | ✅ | ✅ | String/array contains |
Both implementations support all standard comparison operators with identical syntax.
3.2 Logical Operators
| Operator | LiquidJS | Go Liquid | Notes |
|---|---|---|---|
| and | ✅ | ✅ | Logical AND |
| or | ✅ | ✅ | Logical OR |
Syntax:
{% if user.active and user.age >= 18 %}
{% if user.admin or user.moderator %}
Both implementations support logical operators with identical behavior.
3.3 Truthiness
Both implementations follow Liquid's truthiness rules:
Truthy values:
- All values except
falseandnil - Empty strings
""are truthy - Empty arrays
[]are truthy - Zero
0is truthy
Falsy values:
falsenil/null
4. Special Features
4.1 Whitespace Control
| Feature | LiquidJS | Go Liquid | Syntax | Notes |
|---|---|---|---|---|
| Strip left whitespace | ✅ | ✅ | {%- |
Remove left whitespace |
| Strip right whitespace | ✅ | ✅ | -%} |
Remove right whitespace |
| Output strip left | ✅ | ✅ | {{- |
Remove left whitespace |
| Output strip right | ✅ | ✅ | -}} |
Remove right whitespace |
Syntax Example:
{%- if true -%}
Whitespace trimmed
{%- endif -%}
Both implementations support identical whitespace control syntax.
4.2 Dynamic Partials
| Feature | LiquidJS | Go Liquid | Notes |
|---|---|---|---|
| Variable file names | ✅ | ⚠️ Limited | LiquidJS has better support |
| Dynamic partials option | ✅ | ❌ | LiquidJS-specific |
| Expression in filenames | ✅ | ❌ | LiquidJS can evaluate expressions |
LiquidJS:
{% assign template_name = "header" %}
{% include template_name %} {# Dynamic! #}
{% include "files/{{ type }}.liquid" %} {# Expression! #}
Go Liquid:
{% include "header.liquid" %} {# Static filename only #}
4.3 Jekyll Extensions
| Feature | LiquidJS | Go Liquid | API |
|---|---|---|---|
| Jekyll compatibility mode | ✅ | ✅ | Different APIs |
| Dot notation in assign | ✅ | ✅ | Enabled via option |
| Jekyll include behavior | ✅ | ❌ | LiquidJS only |
| Jekyll where filter | ✅ | ❌ | LiquidJS only |
LiquidJS:
const engine = new Liquid({
jekyllInclude: true, // Include vars under 'include' scope
jekyllWhere: true // where filter behavior
})
Go Liquid:
engine := liquid.NewEngine()
engine.SetJekyllExtensions(true) // Enable dot notation
4.4 Error Handling
| Feature | LiquidJS | Go Liquid | Notes |
|---|---|---|---|
| Strict variables | ✅ Configurable | ⚠️ Lenient | LiquidJS can throw on undefined |
| Strict filters | ✅ Configurable | ⚠️ Lenient | LiquidJS can throw on undefined |
| Error context | ✅ Rich | ✅ Good | Both provide line numbers |
| Partial errors | ✅ Configurable | ✅ Returns error | Different strategies |
LiquidJS:
const engine = new Liquid({
strictVariables: true, // Throw on undefined variables
strictFilters: true // Throw on undefined filters
})
Go Liquid:
- Undefined variables return empty string
- Undefined filters cause parse error
- Errors returned via Go error type
4.5 Performance & Resource Limits
| Feature | LiquidJS | Go Liquid | Notes |
|---|---|---|---|
| Template caching | ✅ | ✅ | Both cache parsed templates |
| Memory limits | ✅ Configurable | ⚠️ OS-level | LiquidJS tracks memory |
| Timeout limits | ✅ Configurable | ⚠️ Manual | LiquidJS has renderLimit |
| Parse limits | ✅ Configurable | ❌ | LiquidJS has parseLimit |
LiquidJS:
const engine = new Liquid({
parseLimit: 102400, // 100KB template size
renderLimit: 5000, // 5 second timeout
memoryLimit: 10485760 // 10MB memory
})
Go Liquid:
- No built-in resource limits
- Use Go's context for timeouts
- Memory managed by Go runtime
5. Syntax & Behavior Differences
5.1 Include vs Render
LiquidJS:
include: Shares parent scope, variables accessible both waysrender: Isolated scope, must pass variables explicitly- Recommended: Use
renderfor better encapsulation
Go Liquid:
- Only
includeavailable - Scope controlled via context API
- Variables passed via RenderFile parameters
5.2 Variable Scoping
LiquidJS:
{% assign x = 1 %}
{% include "partial" %} {# Can access x #}
{% render "partial" %} {# Cannot access x #}
{% render "partial", x: x %} {# Must pass explicitly #}
Go Liquid:
{% assign x = 1 %}
{% include "partial" %} {# Scope depends on implementation #}
5.3 Filter Argument Syntax
Both support two syntaxes for filter arguments:
Comma syntax:
{{ "hello" | append: " world" }}
{{ array | slice: 0, 5 }}
Keyword syntax (named parameters):
{{ false | default: "value", allow_false: true }}
5.4 Array Iteration
LiquidJS:
{% for item in array %}
{{ item }}
{% endfor %}
{% for item in hash %}
{{ item[0] }}: {{ item[1] }}
{% endfor %}
Go Liquid:
{% for item in array %}
{{ item }}
{% endfor %}
{% for pair in hash %}
{{ pair[0] }}: {{ pair[1] }}
{% endfor %}
Both iterate over maps/objects as key-value pairs.
6. Limitations & Missing Features
6.1 Go Liquid Limitations
Missing Tags:
- ❌
render- Use include with context isolation - ❌
layout/block- No template inheritance - ❌
echo- Use{{ }}output tags - ❌
liquid- Use standard tag delimiters - ❌
increment/decrement- Manual counter management - ❌ Inline comments (
{% # %}) - Use{% comment %}
Missing Filters:
- ❌ Expression filters (
where_exp,reject_exp, etc.) - ❌ Advanced array filters (
group_by,sum,push,pop, etc.) - ❌ Date formatting filters (use
datewith strftime) - ❌ URL filters (
slugify,cgi_escape,uri_escape) - ❌ Base64 filters
- ❌
remove_last,replace_last - ❌
normalize_whitespace,number_of_words - ❌
at_least,at_most - ❌
array_to_sentence_string - ❌
to_integer
API Limitations:
- Manual context management for timeouts
- No built-in memory/parse size limits
- Less flexible dynamic partials
6.2 LiquidJS Limitations
None identified - LiquidJS appears to be a more feature-complete implementation with:
- All standard Liquid tags and filters
- Additional Jekyll-compatible features
- Expression-based filters
- Better resource limit controls
- More flexible partial system
7. Extensibility
7.1 Custom Filters
LiquidJS:
engine.registerFilter('shout', (v) => v.toUpperCase() + '!!!')
// Async filter
engine.registerFilter('fetchData', async (url) => {
const response = await fetch(url)
return response.json()
})
Go Liquid:
engine.AddFilter("shout", func(s string) string {
return strings.ToUpper(s) + "!!!"
})
7.2 Custom Tags
LiquidJS:
engine.registerTag('upper', {
parse(token) {
this.str = token.args
},
render(ctx) {
const str = this.liquid.evalValue(this.str, ctx)
return str.toUpperCase()
}
})
Go Liquid:
engine.AddTag("upper", func(source string) (func(io.Writer, render.Context) error, error) {
return func(w io.Writer, ctx render.Context) error {
// Parse and render logic
}, nil
})
7.3 Custom File Systems
LiquidJS:
const engine = new Liquid({
fs: {
readFileSync: (file) => templates[file] || '',
existsSync: (file) => templates.hasOwnProperty(file),
resolve: (root, file) => file
}
})
Go Liquid:
type TemplateStore interface {
ReadTemplate(name string) ([]byte, error)
}
engine.SetTemplateStore(myStore)
Appendix: Complete Filter List
LiquidJS Filters (85)
Array (26): abs, append, array_to_sentence_string, at_least, at_most, base64_decode, base64_encode, capitalize, ceil, cgi_escape, compact, concat, date, date_to_long_string, date_to_rfc822, date_to_string, date_to_xmlschema, default, divided_by, downcase, escape, escape_once, find, find_exp, find_index, find_index_exp
Continuation: first, floor, group_by, group_by_exp, has, has_exp, inspect, join, json, jsonify, last, lstrip, map, minus, modulo, newline_to_br, normalize_whitespace, number_of_words, plus, pop, prepend, push, raw, reject, reject_exp, remove, remove_first, remove_last, replace, replace_first, replace_last, reverse, round, rstrip, shift, size, slice, slugify, sort, sort_natural, split, strip, strip_html, strip_newlines, sum, times, to_integer, truncate, truncatewords, uniq, unshift, upcase, uri_escape, url_decode, url_encode, where, where_exp, xml_escape
Go Liquid Filters (45)
All Filters: abs, append, capitalize, ceil, compact, concat, date, default, divided_by, downcase, escape, escape_once, first, floor, inspect, join, json, last, lstrip, map, minus, modulo, newline_to_br, plus, prepend, remove, remove_first, replace, replace_first, reverse, round, rstrip, size, slice, sort, sort_natural, split, strip, strip_html, strip_newlines, times, truncate, truncatewords, type, uniq, upcase, url_decode, url_encode
End of Comparison Document
Couldn't wait actually, I implemented it in https://github.com/osteele/liquid/pull/129
For the record I just released a full feature parity - Liquid Golang implementation - of the official Ruby lib: https://github.com/Notifuse/liquidgo