## Why use this? If you've ever seen a jekyll boilerplate, or another project that uses [liquid](https://github.com/Shopify/liquid) templates and wished it was written in [handlebars][], this is your solution! - 100% of the tags mentioned in the [shopify liquid documentation](http://shopify.github.io/liquid/) convert to handlebars syntax - easily migrate any liquid theme or boilerplate - use more powerful and flexible handlebars helpers instead of liquid filters **Please [create an issue](../../issues/new) if you find a tag that doesn't convert correctly, and I'll add support. Thanks!** ## Usage ```js const converter = require('liquid-to-handlebars'); // Converts this liquid console.log(converter.convert('Price: ${{ product_price | default: 2.99 }}')); // To this handlebars //=> 'Price: ${{default product_price 2.99}}' ``` You will also need to include any missing handlebars helpers that provide similar functionality to the liquid filters that are being replaced. For example: ```js const handlebars = require('handlebars'); handlebars.registerHelper('default', function(a, b) { return a || b || ''; }); const fn = handlebars.compile('Price: ${{default product_price 2.99}}'); console.log(fn()); //=> 'Price: $2.99' console.log(fn({default_price: '4.99'})); //=> 'Price: $4.99' ``` ## Migration debugging _Once your liquid templates are converted to handlebars, if you attempt to render all of the templates with handlebars without any additional work, it's a good bet that you'll receive a bunch of errors from missing helpers._ Save yourself a bunch of time and frustration by following these steps: ### Step 1: Add starter helpers Add the following to your app: ```js const handlebars = require('handlebars'); // override handlebars' built-in `helperMissing` helper, so that we // can easily see which helpers are missing and get them fixed handlebars.registerHelper('helperMissing', function() { const opts = [].slice.call(arguments).pop(); console.log(`missing helper {{${opts.name}}}`); }); ``` ### Step 2: Run handlebars Now, when you run handlebars, if you see a message like this: ```js missing helper {{foo}} ``` You can either create the `foo` helper from scratch, or use a helper library that already includes the helpers you need. Any of the following libraries may be used, but the [liquid-filters][] library might be most useful (during migration, at least). - [liquid-filters][] - includes a bunch of utility javascript functions that can be registered as handlebars helpers to provide parity with the built-in liquid filters - [template-helpers][] - generic helpers that can be used with any template engine. - [handlebars-helpers][] - more than 150 handlebars helpers **Examples** ```js const handlebars = require('handlebars'); const filters = require('liquid-filters'); const helpers = require('template-helpers'); handlebars.registerHelper(filters()); handlebars.registerHelper(helpers()); ``` ## Conversion Examples There are **many more examples** in the [docs folder](./examples.md), as well as [test/fixtures](./test/fixtures) and [test/expected](test/expected). ### Conditionals **basic operators** From this liquid: ```liquid {%% if product.type == "Shirt" or product.type == "Shoes" %} This is a shirt or a pair of shoes. {%% endif %} ``` To this handlebars: ```handlebars {{#if (or (is product.type "Shirt") (is product.type "Shoes"))}} This is a shirt or a pair of shoes. {{/if}} ``` **boolean** From this liquid: ```liquid {%% if settings.fp_heading %}

{{ settings.fp_heading }}

{%% endif %} ``` To this handlebars: ```handlebars {{#if settings.fp_heading}}

{{ settings.fp_heading }}

{{/if}} ``` **case** From this liquid: ```liquid {%% case handle %} {%% when 'cake' %} This is a cake {%% when 'cookie' %} This is a cookie {%% else %} This is not a cookie/cake {%% endcase %} ``` To this handlebars: ```handlebars {{#is handle 'cake'}} This is a cake {{else is handle 'cookie'}} This is a cookie {{ else }} This is not a cookie/cake {{/is}} ``` Requires the ["is" helper][handlebars-helper-is]. **else** From this liquid: ```liquid {%% if username and username.size > 10 %} Wow, {{ username }}, you have a long name! {%% else %} Hello there! {%% endif %} ``` To this handlebars: ```handlebars {{#if (and username (gt username.size 10))}} Wow, {{ username }}, you have a long name! {{else}} Hello there! {{/if}} ``` **contains** From this liquid: ```liquid {%% if product.title contains 'Pack' %} This product's title contains the word Pack. {%% endif %} ``` To this handlebars: ```handlebars {{#if (contains product.title "Pack")}} This product's title contains the word Pack. {{/if}} ``` ### Arrays **Basic loops** From this liquid: ```liquid {%% for user in site.users %} {{ user }} {%% endfor %} ``` To this handlebars: ```handlebars {{#each site.users as |user|}} {{ user }} {{/each}} ``` **Accessing specific items in arrays** From this liquid: ```liquid {{ site.users[0] }} {{ site.users[1] }} {{ site.users[3] }} ``` To this handlebars: ```handlebars {{get site.users 0}} {{get site.users 1}} {{get site.users 3}} ``` ### Filters > Filters are converted to [handlebars subexpressions](http://handlebarsjs.com/expressions.html#subexpressions) From this liquid: ```liquid {{ "Ground control to Major Tom." | split: "" | reverse | join: "" }} ``` To this handlebars: ```handlebars {{join (reverse (split "Ground control to Major Tom." "")) ""}} ``` **Many more examples** in the [docs folder](docs) and [unit tests](test). ## What is this? This is a tool for converting projects that use [liquid](https://github.com/Shopify/liquid) templates to use [handlebars][] templates.