Breaking Change - Async function removal

Deployed: 2/22/24

We are removing the Twig async function and its associated async_templates_script.

The initial idea behind the async function was to serve as a convenience function for theme developers to load in un-cacheable resources (e.g. cart) without hampering their initial page load.

However we discovered that automatic handling of scripts within the async template was cumbersome. Some apps/themes require that javascript is loaded and run before the content and some instances require the javascript to run after the content is inserted into the DOM.

It was impossible to build in automatic handling of scripts without having the exact information required to tell us when a script is supposed to execute. Attempting to handle all cases resulted in brittle and over-complex solutions that may not handle all cases.

We entertained the idea of not doing any script handling within async templates, but we realized that there were very few use-cases where async templates would not have javascript. For example, why would you want to load a cart if you were not going to apply any JS powered actions on it?

Migration path

The expectation will be for theme developers to write javascript to manually call the Template API to load and render any uncacheable resources.

Here is an example of the migration being done in Brisk.

Before

Parent template

{{ async_templates_script() }}

<div>
	Async Demo
	{{ async('components/async/item', "item-template", {
		props: {
			item: item
		}
	}) }}
</div>

{% schema %}
{
	"item": {
		"type": "item-query"
	}
}
{% endschema %}

Item async template

{% async:content %}
	Name: {{ item.name }}
{% endasync %}

{% async:loading %}
	<div>
		loading...
	</div>
{% endasync %}

{% schema %}
{
	"item": {
		"type": "item",
		"optional": true
	}
}
{% endschema %}

After

Parent template

<div id="item-placeholder">
    Loading...
</div>

<script>
    document.addEventListener('DOMContentLoaded', async () => {
        const text = await window.SquareWebSDK.template.getTemplate({
            template: 'components/partials/item',
            props: {
                item: {{ itemQuery | json_encode }}
            },
        })

        document.getElementById('item-placeholder').innerHTML = text;
    });
</script>

{% schema %}
{
	"itemQuery": {
		"type": "item-query"
	}
}
{% endschema %}

Item template

<p> Name: {{ item.name }}</p>

{% schema %}
{
	"item": {
		"type": "item",
		"optional": true
	}
}
{% endschema %}