Including clientlib with async/defer, but ensuring it's included only once?

cecilyd30905463

30-10-2019

I'm trying to include clientlibs with async or defer attributes in the script tag. However, I also want to ensure that each clientlib is not loaded more than once. So if I include the clientlib within a component's code and the component is used multiple times on a page, the script tag should only appear in the first instance of the component.

The default way of including clientlibs (using /libs/granite/sightly/templates/clientlib.html) does seem to prevent the same script from being loaded more than once, but doesn't support async/defer.

I was able to get async/defer working using the https://github.com/nateyolles/aem-clientlib-async example that I've seen mentioned here. However, this code does not prevent the script from being loaded and executed multiple times if there are multiple components on the page.

Does anyone know how I might accomplish this? I would appreciate any insight!

Accepted Solutions (1)

Accepted Solutions (1)

Nirmal_Jose

MVP

31-10-2019

We can have multiple options in terms of loading the clientlibs for components -

1. all component clientlibs loaded separately - more number of requests , less size

2. having a single clientlibs combining all component clientlibs and loaded on the template level. - more size, but less size

Is there any reason you are not going through the bundling way (option 2 - Using Client-Side Libraries ) and going through async and defer for that one. Keen to understand more about it.

Answers (4)

Answers (4)

Nirmal_Jose

MVP

03-11-2019

Heya,

AFAIK, its always good to have lesser requests than bigger file unless your webapp is going to used over lesser bandwidth networks. Moreover, even though repeated javascript file requests are served from browser cache, repeated JS execution happens for evaluation.  (ref https://developer.yahoo.com/performance/rules.html#js_dupes )

All Adobe reference points suggests to concatenate your clientlibs to a single file and gets included in your template header and footer. For example, refer to
/apps/weretail/components/structure/page/customfooterlibs.html
/apps/weretail/components/structure/page/customheaderlibs.html

The latest maven archetype 21 has a frontend node module integrated into the application code, but that too does the concatenation. (https://github.com/adobe/aem-project-archetype)

Usage of clientlibs is best described at AEM Developer Learning : ClientLibs in AEM 6.3 - Part1

In case you have so many heavy clientlib components which you don't want to load on all the pages, you can follow the below approach.

1. Categorise your component clientlibs wth 'categories' property based on the grouping of components. You can think of core, homepage etc
2. Define templates for your usecases and overlay customfooterlibs and customerheaderlibs to include the required category.

As a best practice, have multiple clientlibs for types of clientlibs (vendor, module, page-specific ) as https://stackoverflow.com/questions/15236767/one-big-javascript-file-or-multiple-smaller-files#answe... . This can help later if you want to implement a cache buster kind of a capability for your applications scripts as they change very often.

But this goes against the capability of editable templates where you can update the policy to add a new component to the page. So overall it differs as per the use case of each project based on the priority between page load and agility as well

cecilyd30905463

01-11-2019

Thanks for the response. The only way I could find of doing #1 (including clientlibs on a per-component basis) involved putting the include in the component HTL, rather than in the document head or at the end of the body. This is why I started to look into how to add async/defer in the first place, since I didn’t want a script in the middle of the page to block the rendering.

Ideally, I wanted to keep the number of requests down by creating bundles for groups of components that are loaded as needed rather than a separate file for each component.

The reason I didn’t want to do #2 (throw everything in a single component bundle) was to keep the page size down and not load a lot of JS/CSS that is never used.

I’m relatively new to AEM development so it’s possible that I’m missing something. I did consider whether creating different static page templates and loading different bundles there would be the way to go - this might be a more "AEM way" of doing things? Potential issues with this would be a) being overly restrictive for marketers in terms of what components they can use, and b) situations where a resource-heavy component is only used in a small percentage of pages of its template type.

Thanks again, looking forward to hearing your thoughts on this!