Sightly Optimisations

I recently performed an audit for a client of their AEM development and deployment. Part of that audit covered their AEM page renderers and components. They had started their development with AEM 6 which allowed them to use the new Sightly interpretor for their components. The following is some items I picked up that are generic enough to share.

Sightly != JSP

It may sound obvious, but Sightly is not JSP. This means a S(l)ightly different mindset is required when developing these files. This mostly revolves around the use of control structures that are such a definite part of Java in JSP, but are more elegant in Sightly.

data-sly-unwrap as control structures

In this audit I repeatedly saw the use of an extra <div> just to wrap a conditional. This is basically taking the logic from a JSP script and converting it to Sightly. Imagine the following code in Sightly:

<div data-sly-test="${myUseObject.showIFrame}" data-sly-unwrap>
  <IFRAME id="XXX" class="hide" src=""></IFRAME>
</div>

You can imagine this as straight JSP:

<% if (myUseObject.showIFrame) { %>
  <IFRAME id="XXX" class="hide" src=""></IFRAME>
<% } %>

when it could be written like this:

<IFRAME
  data-sly-test="${myUseObject.showIFrame}" 
  id="XXX" class="hide" src=""></IFRAME>

A more extreme example is this:

<a class="sitemap-item" href="${item.path}.html">
    <div data-sly-test="${item.path == currentPage.path}" data-sly-unwrap>
        <b class="orange" alt="Current Page">
    </div>
    <div data-sly-test="${item.navigationTitle}" data-sly-unwrap>
        ${item.navigationTitle}
    </div>
    <div data-sly-test="${!item.navigationTitle}" data-sly-unwrap>
        ${item.title}
    </div>
    <div data-sly-test="${item.path == currentPage.path}" data-sly-unwrap>
        </b>
    </div>
</a>

Which could be written like this:

<a class="sitemap-item1" href="${item.path}.html">
  <b 
    data-sly-unwrap="${item.path != currentPage.path}" 
    data-sly-text="${item.navigationTitle || item.title}"
    class="orange" alt="Current Page">
  </b>
</a>

Here using the data-sly-unwrap with a conditional test, the <b> tag is output only if the page is the current page.

Looping

In the following snippet you can see that extra <div>‘s have been used again as a control structure, for outputting a standard unordered list.

<div 
  data-sly-test="${parent.listChildren}" 
  data-sly-list.child="${parent.listChildren}" 
  data-sly-unwrap>
    <div 
      data-sly-test="${!child.hideInNav}"
      data-sly-unwrap>
      <ul>
        <li>
          ..
        </li>
      </ul>
    </div>
</div>

Assuming that having an individual <ul> for each list item was a mistake, the code can be optimised like this:

<ul data-sly-list.child="${parent.listChildren}">
  <li data-sly-test="${!child.hideInNav}">
    ..
  </li>
</ul>

Inline conditionals

Using inline conditionals can help simply your code:

<div data-sly-test="${myUseClass.getVertical}">
  <input type="hidden" id="verticalTab" value="true" name="verticalTab"/>
</div>
<div data-sly-test="!${myUseClass.getVertical}">
  <input type="hidden" id="verticalTab" value="false" name="verticalTab"/>
</div>

like this:

<input
  type="hidden"
  id="verticalTab"
  value="${myUseClass.getVertical ? 'true' : 'false'}"
  name="verticalTab" />

Or as a more extreme example:

<ul>
  <div data-sly-list="${myUseClass.tabs}" data-sly-unwrap>
    <div data-sly-test="${!myUseClass.getVertical}" data-sly-unwrap>
      <li style="width:${myUseClass.tabWidth @ context='styleToken'}%">
        <a href='#tabs-${itemList.index @ context="scriptString"}'>
          ${item.label @ context='html'}
        </a>
      </li>
    </div>
    <div data-sly-test="${myUseClass.getVertical}" data-sly-unwrap>
      <li>
        <a href='#tabs-${itemList.index @ context="scriptString"}' >
          ${item.label @ context='html'}
        </a>
      </li>
    </div>
  </div>
</ul>

To this (using ‘join’ operator on an array to concatenate the string):

<ul data-sly-list="${myUseClass.tabs}">
  <li 
    style="${myUseClass.vertical ? [] : ['width', myUseClass.tabWidth] @ join=': ', context='attribute'}">
    <a href='#tabs-${itemList.index @ context="scriptString"}'>
      ${item.label @ context='html'}
    </a>
  </li>
</ul>

Pass WCMUse Objects to templates

The client was following best practice by using templates for their repetitive code, but in some cases I noticed they were passing a WCMUse class name through to the template so that it could be instantiated with a data-sly-use. However in all cases I could find this WCMUse class was already instantiated in the Sightly file calling the template – resulting in two instantiations of the object.

For example

<!-- Component Sightly file -->
<div
  data-sly-use.formTpl="../formTemplates.html"
  data-sly-use.formElem="com.tbscg.sightly.test.TextBox">
  <div
    class="form_text_label"
    data-sly-call="${formTpl.printLabel @ elemClass='com.tbscg.sightly.test.TextBox'}">
  </div>
   ...
</div>

<!-- formTemplates.html -->
<template data-sly-template.printLabel="${@ elemClass}">
  <div
    data-sly-use.formElem="${elemClass}"
    data-sly-test="${formElem.hideTitle}"
    class="leftcol">
    <div class="label">
      <label
        class="text-light"
        for="${formElem.id}"
        data-sly-text="${'{0} {1} :' @ format=[formElem.title, (formElem.required) ? '*' : '']}">
      </label>
    </div>
  </div>
</template>

could be improved like this:

<!-- Component Sightly file -->
<div
  data-sly-use.formTpl="../formTemplates.html"
  data-sly-use.formElem="com.tbscg.sightly.test.TextBox">
  <div
    class="form_text_label"
    data-sly-call="${formTpl.printLabel @ formElem=formElem}">
  </div>
   ...
</div>

<!-- formTemplates.html -->
<template data-sly-template.printLabel="${@ formElem}">
  <div
    data-sly-test="${formElem.hideTitle}"
    class="leftcol">
    <div class="label">
      <label
        class="text-light"
        for="${formElem.id}"
        data-sly-text="${'{0} {1} :' @ format=[formElem.title, (formElem.required) ? '*' : '']}">
      </label>
    </div>
  </div>
</template>

Sightly Resources

The original Intro to Sightly posts from Feike: Part 1, Part 2, Part 3, Part 4 & Part 5

Official Sightly AEM Documentation

Thanks for reading, I hope this helps in your AEM6 development. If you have any questions, please post them in the comments below.