Asynchronous HST components and containers - BloomReach Experience - Open Source CMS

This article covers a Hippo CMS version 10. There's an updated version available that covers our most recent release.

13-05-2015

Asynchronous HST components and containers

Introduction

Both HST components and HST containers can be rendered asynchronously out-of-the-box. Common use cases are:

  • Content that is customized for a particular visitor (e.g. a "stores near you" component)

  • Content that accesses a potentially slow external service (e.g. a Twitter feed)

  • Content that should not be cached or indexed by search engines

Only live requests will actually load components asynchronously. For preview requests or views of the application in the channel manager in the CMS, components that are marked to load asynchronously will be rendered synchronously.

Configuring an HST component to be rendered asynchronously

Add the following JCR property to an hst:component or hst:container node to make it asynchronous:

- hst:async = true

Pages that contain asynchronous components and/or containers will automatically include a Javascript file in the response. The javascript file will execute separate Ajax calls to fetch the rendered output of each asynchronous component and/or container. The only thing that needs to be present in the root renderer (jsp / freemarker) template is the following:

1) If you already have in your renderer the inclusion of hst:headContributions, then make sure you add "scripts" to the categoryExcludes. If you already have categoryExcludes, it can contain multiple categories separated by a comma.

<hst:headContributions categoryExcludes="scripts" xhtml="true"/>

2) And make sure that at the end of the renderer, for example just before the closing of the html body ( </body>) you include the following:

<hst:headContributions categoryIncludes="scripts" xhtml="true"/>

The latter will make sure that the loading of asynchronous parts in the html through ajax calls is triggered

Supported asynchronous modes

When configuring hst:async = true on a hst component, the default asynchronous rendering mode is by a client side ajax request that fetches the content of the asynchronous components and aggregates it in the page when done. However, you might not want the aggregation of the page to be done on the client. In that case you can also opt for ESI or SSI asynchronous modes to aggregate the asynchronous components on the server, for example in some CDN, squid, varnish, httpd, etc. The supported asynchronous modes are:

  1. ajax (default)
  2. ssi (Server Side Includes)
  3. esi (Edge Side Includes)

You can set the asynchronous mode via property  hst:asyncmode. For example

​hst:asyncmode = esi

Restrictions

Asynchronous HST components and containers have the following restrictions:

  • All descendant components of an asynchronous component will be rendered in the asynchronous request for the asynchronous ancestor.

  • Asynchronous components should be independent of synchronous (i.e. 'normal') HST components. For example, you cannot have a synchronous component put something in the request context that is needed by an asynchronous component. It is possible with marking the hst:component to also have hst:standalone = false but this is strongly discouraged. Also see HST component rendering.

  • Asynchronous components cannot contribute hst:headContributions since they are not rendered (they are later async rendered) when the headContributions are written to the html.

  • If a client does not have Javascript enabled, asynchronous components will not be rendered if the async loading mode is ajax

A special case of the last restriction is that the output of an asynchronous component will not be indexed by search engines, as search engine bots do not execute Ajax calls. Since asynchronous calls are typically used for parts that are, for example, completely personalized, or very much depend on some external service like a Twitter feed, this is in general even better.

Although mentioned above as the third restriction, please thus realize that:

Asynchronous components cannot contribute hst:headContributions

Async components nested below async components

When marking a hst:component as hst:async = true that already has an ancestor hst:component that is marked to be aynchronous, then, when the ancestor is loaded asynchronously, its descendants are directly loaded as well, even if the descendant is marked to be asynchronous. Thus, nested asynchronous HST components are allowed, but an asynchronously rendered component will render all its descendants as well regardless whether they are asynchronous or not.

How it works

Marking an HST component with hst:async = true, triggers the HST request processing to skip the doBeforeRender and render method of the async component and all its descendant. Instead, it will inject in the response a placeholder div with an id that contains a HST component rendering URL, and a class attribute with some obfuscated value. The aggregation valve also adds a headContribution for the asynchronous Javascript loading that is added to the html through <hst:headContributions categoryIncludes="scripts" xhtml="true"/>.

Troubleshooting

If you asynchronous component does not get shown in the page (and you did not configure hst:asyncmode to be esi or ssi), check out with browser development tools whether an ajax network request is done. It should be a request that contains something like

?_hn:type=component-rendering&_hn:ref=r6_r1

Note : where the _hn:ref value r6_r1 is different per component. The _hn:type=component-rendering indicates that the ajax call should be done by a Component Rendering URL

If you do not see this request, check out the html code of the page. It should contain in the html/head a javascript element containing something like

a425658310.b425658310.AsyncPage = { .....

and at the end of the html page it should contain

<script type="text/javascript">
//<![CDATA[
a425658310.b425658310.AsyncPage.load();
//]]>
</script>

The part  a425658310.b425658310 is different per project and randomly created. If the snippet containing  a425658310.b425658310.AsyncPage.load(); is in the html/head, asynchronous ajax calls for components won't work. To fix this problem, you need to add to the hst:headContributions in the base page template in the <head> element the categoryExcludes scripts and add to the bottom  categoryIncludes scripts. The simplified archetype project base template looks as follows to make sure asynchronous components work out of the box. 

<!doctype html>
</html>
  <head>
    <snip/>
    <@hst.headContributions categoryExcludes="htmlBodyEnd, scripts" xhtml=true/>
  </head>
  <body>
    <snip/>
    <@hst.headContributions categoryIncludes="htmlBodyEnd, scripts" xhtml=true/>
  </body>
</html>

Thus, make sure to exclude  script category in the top and include it in the bottom

 

Did you find this page helpful?
How could this documentation serve you better?
On this page
    Did you find this page helpful?
    How could this documentation serve you better?