Using Client Libraries and Avoiding jQuery Headaches

05287_Using Client Libraries and Avoiding jQuery Headaches in AEM
AEM provides a feature called client libraries to allow for managing CSS and JavaScript in your site.

  • It allows you to bundle your files into one large file so you have fewer requests on your pages.
  • It allows you to minify them to make the download less expensive and faster.
  • It allows you to “categorize” them so you can define dependencies and control the order in which they are loaded (this is mainly important for JavaScript).
  • It allows you to store the JavaScript that is component specific in the repository location of the components (/apps/projectname/components/componentname/clientlibs). You can then load them by referring to their category from the “dependencies” or “embed” property of the clientlibs in your front-end design under /etc/designs/projectname/clientlibs.

App-specific client library folders
It is a best practice to keep all application-related files in their application folder below /apps. It is also a best practice to deny access for website visitors to the /apps folder. To satisfy both best practices, create a client library folder below the /etc folder that embeds the client library
that is below /apps.

However there is one snag you need to be very wary of…

The front-end designers tend to develop their code based on a recent version of jQuery and forget to mention this as a dependency (sometimes this jQuery library is not even provided together with the front-end design)! What this means is that all the custom JavaScript you received needs this version of jQuery to work properly.

Most of Adobe Experience Manager’s edit functionalities are JavaScript-based and it also uses jQuery! However, AEM 6.0 comes bundled with jQuery version 1.11.0, which is kind of prehistoric.

/etc/clientlibs/foundation/jquery: categories: cq.jquery, dependencies:
/etc/clientlibs/granite/jquery/granite: categories: granite.jquery, dependencies:
jquery, granite.utils
/etc/clientlibs/granite/jquery: categories: jquery

You are loading the jQuery library from AEM itself when you include the following line in a (custom) page component:

as this standard JSP contains the following code:

But even if you don’t load it explicitly this way, if you load other client libraries from Adobe Experience Manager, it is quite possible that some of them depend on “cq.jquery” so the standard jQuery will get loaded after all.

So the extra challenge is:

  1. Make sure the correct jQuery version required by the front-end design is added to the client libraries used by your AEM site (to avoid getting strange design issues that do not occur in the original front-end design)
  2. Make sure it is loaded before any custom code (component-specific JavaScript, front-end design JavaScript)
  3. Make sure it doesn’t conflict with the jQuery functionality of AEM itself

Load correct jQuery version into the client libraries used by the design of your site

  1. Put all CSS and JavaScript of the front-end design into a “clientlibs” folder under “/etc/designs/projectname” and categorize it as “sitename.frontend” (add a multivalue String property “categories”)
  2. Add the correct front-end jQuery library to the client libraries used by the design of your site to make sure it gets loaded, but…
  3. Due to the dependencies of other (standard) client libraries, the old Adobe Experience Manager jQuery library version will still be loaded and this can lead to nasty conflicts.
    1. Do not attempt to categorize your new jQuery client library as cq.jquery in the hopes of preventing the old one from loading. It will still do. The only way this might work is to use the identical folder structure and file names as the standard AEM jQuery library. But it wouldn’t make sense and be very confusing to rename a newer version to “1.11.0/jquery-1.11.0.js”. So just don’t.
    2. Also it may not be a good idea to try to overlay the AEM native jQuery library in the first place as it is part of the platform and we may break native functionality this way. Even if we succeeded to “upgrade” the native jQuery library, all sites running on the server would then be forced to use this version and each site design could depend on another jQuery version.
    3. Do not attempt to create a custom overlay of /libs/foundation/components/page/stats.jsp so it no longer includes cq.jquery, but apps.yourproject.jquery and provide a specific clientlibrary folder under /etc/designs/projectname/clientlibs. As other AEM native client libraries will still mention dependency “cq.jquery”, the AEM native jQuery will keep on getting loaded.
  4. Accept that loading the native AEM jQuery 1.11.0 version is unavoidable.

Load correct jQuery version before any custom JavaScript is loaded (component-specific or general front-end design stuff).

  1. Put the correct jQuery library inside its own “jquery” subfolder in your “clientlibs” folder and categorize it as “sitename.jquery” (add a multivalue String property “categories”).
    1. Put the correct jQuery library inside its own “jquery” subfolder in your “clientlibs” folder and categorize it as “sitename.jquery” (add a multivalue String property “categories”) and make it depend on the AEM native client library “jquery” (add a multivalue String property “dependencies=’[jquery]’”) to make sure this one is loaded before the your custom front-end jQuery library.
  2. Categorize all “clientlibs” folders on your custom components as “projectname.components” (add a multivalue String property “categories”). (You can optionally categorize them as “projectname.components.componentname” as well, should you need to load only clientlibs for a specific component somewhere.)
  3. Now the magic words… To the “clientlibs” folder of your site under “/etc/designs/projectname”.
    1. Add a multivalue String property “dependencies=’[sitename.jquery]’” to make sure the jQuery library required by your front-end design is loaded before your own site design client libraries (and therefore before any custom JavaScript).
    2. Add a multivalue String property “embed=’[sitename.components,]’” to make sure the client libraries of your custom components are loaded after the jQuery library of your front-end design but can still be bundled together with your other site design client libraries into one big JavaScript file and minified.
  4. This still leaves that fact that you are loading two different jQuery versions at the same time and both probably use $, which is a cause for conflicts.

– Replaced all $ with $j in components related .js file which didn’t refer to AEM, CQ, Granite specific .js libraries.

Load correct jQuery version into the client libraries used by the design of your site.

  1. Replace all $ in your custom JavaScript (component-specific clientlibs with JavaScript files, front-end design JavaScript files) with another reference like “$j” to avoid that your custom code uses the native AEM jQuery that is assigned to $ and $CQ.
    1. Also communicate this to your front-end designer so he never ever uses $ in their front-end design for your Adobe Experience Manager project again.
  2. Lift the conflict between your front-end jQuery library and the one native to AEM ( -> If for some reason two versions of jQuery are loaded (which is not recommended), calling $.noConflict( true ) from the second version will return the globally scoped jQuery variables to those of the first version.)
    1. Add a new JavaScript file “jquery.noconflict.js” to the “source” folder inside the “jquery” clientlib folder (which you created in the first point of the previous topic) in your front-end design “clientlibs” Make sure it gets loaded by mentioning it in the accompanying “js.txt” file. Inside this new JavaScript you put the code.
var $j = jQuery.noConflict(true);

Add debug code to the body of your generic page component to be able to easily
check if the correct jQuery version is being used.  Add code that will:

  1. Print the version of the jQuery libraries assigned to references $ and $CQ (hopefully the native Adobe Experience Manager one)
  2. Then load the custom JavaScript from your front-end design client libraries, which
    1. First loads the native AEM jQuery if it wasn’t already loaded (your front-end design depends on your custom design jQuery, which depends on the native AEM jQuery)
    2. Then loads your custom design jQuery and at the end executes the noConflict code, which assigns it to reference $j
    3. Then adds the custom JavaScript from your custom components
    4. And finally loads all remaining custom JavaScript from your front-end design
  3. Then prints the version of the jQuery libraries assigned to references $, $CQ and $j. Here you should see that $ and $CQ are still assigned to the native AEM jQuery version and the $j to your custom design jQuery version.
<%-- JQuery library loading debug code

Before $.noConflict(true)

--%> <%-- JQuery library loading debug code --%>

For further client libraries debugging tools, check out this other AEM Podcast article on this topic.

ivo_eersels2Author bio
Ivo Eersels is an industrial engineer and has been a software engineer on the Intershop Suite 6 E-commerce platform at Osudio, one of Europe’s largest e-business specialists, since 2007. He has been working with AEM since 2013. Ivo plays a large role in setting up projects, DTAP servers, deployment strategies, guidelines, and development.