AEM in 40 Days
CalendarPhase 3 · Building with the Archetype

Day 19 of 40

WKND: Client-Side Libraries

Categories, embed, dependencies, allowProxy and the proxy servlet

~45 min read1 video2 source pages

By the end of today you should be able to

  1. Create a client library and understand categories, dependencies and embed
  2. Explain allowProxy and why clientlibs are served from /etc.clientlibs
  3. Include clientlibs correctly from a page component
  4. Debug a clientlib that is not loading

What a client library is

A client library (clientlib) is AEM's mechanism for serving CSS and JavaScript. It is a node of type cq:ClientLibraryFolder containing your source files plus two text files listing which of them to include and in what order:

/apps/wknd/clientlibs/clientlib-site
  .content.xml        jcr:primaryType = "cq:ClientLibraryFolder"
                      categories = ["wknd.site"]
                      allowProxy = true
  css.txt
  js.txt
  css/
  js/

css.txt lists files relative to a base directory:

#base=css
site.css
components.css

AEM concatenates and (in production) minifies the listed files into a single response, so the browser makes one request per category rather than one per file.

Categories, dependencies, embed

  • categories — the name(s) by which this library is requested. Multi-valued: a library can belong to several categories.
  • dependencies — categories that must be loaded before this one. They are included as separate requests.
  • embed — categories whose content is copied into this library's output. One request, contents merged.
dependencies vs embed

dependencies says "load that too, first". embed says "fold that into me". Embed is how you expose a library that lives somewhere non-public: embed it into a proxy-enabled library and its code is served without exposing its path.

allowProxy and /etc.clientlibs

Clientlibs live under /apps, but /apps must not be readable by anonymous users on publish — exposing it would leak your component structure. The proxy servlet resolves this: with allowProxy = true, a library at /apps/wknd/clientlibs/clientlib-site is served from /etc.clientlibs/wknd/clientlibs/clientlib-site.css.

Nothing actually lives at /etc.clientlibs — it is a virtual path the servlet maps back to /apps (and /libs). Your Dispatcher must allow /etc.clientlibs in its filters, which the standard configuration does.

Missing CSS on publish only

Styles work on author and vanish on publish. The cause is almost always allowProxy not set to true: on author you are logged in and can read /apps directly, while an anonymous visitor on publish cannot.

Including clientlibs

The modern approach uses the Core Components clientlib helper, which gives you control over loading strategy:

<sly data-sly-use.clientlib="core/wcm/components/commons/v1/templates/clientlib.html"/>

<!-- In <head> -->
<sly data-sly-call="${clientlib.css @ categories='wknd.site'}"/>

<!-- Before </body> -->
<sly data-sly-call="${clientlib.js @ categories='wknd.site'}"/>

<!-- Both at once -->
<sly data-sly-call="${clientlib.all @ categories='wknd.site'}"/>

Splitting CSS into the head and JS before the closing body tag is the standard performance shape, and it is why clientlib.all is usually the wrong choice for a page component.

Debugging

  1. Does the category resolve? Go to /libs/granite/ui/content/dumplibs.html — it lists every registered library and its category. A typo in categories shows up instantly.
  2. Is it proxy-enabled? Request /etc.clientlibs/<path>.css directly. A 404 means allowProxy is missing.
  3. Are the files listed? A file present in the folder but absent from css.txt is simply not served. This is a very common oversight.
  4. Is it cached? Append a cache-busting query or flush the Dispatcher; stale clientlibs are common after a deploy.
  5. dumplibs.test.html lets you check which libraries a given category actually pulls in, including embeds.

How ui.frontend fits

In an archetype project you rarely hand-write clientlib-site. The ui.frontend webpack build produces it: you write Sass and ES modules there, and the build generates the clientlib folder — css.txt, js.txt and all — into ui.apps. Editing the generated clientlib directly is a mistake; the next build overwrites it.

Today's takeaway

Categories name a library, dependencies load alongside, embed folds in. allowProxy = true and /etc.clientlibs are what make it work for anonymous visitors on publish.

Watch

Adobe's own videos for this topic. They load only when you press play.

Component Basics - Client-side Libraries 35

Read on Experience League

The primary sources these notes are drawn from.

Your notes

Saved automatically to this browser.

Check yourself

10 questions on today's material. 80% to pass.

Take the quiz