The Duplicate jQuery and the 30-Day Clientlib Cache
A page loads 14 CSS and JavaScript requests totaling 2.8 MB. The main clientlib acme.site has category acme.site. It embeds acme.vendor and acme.components, and it also declares dependencies on those same two categories. Each component clientlib declares a dependency on acme.site so that it can use global styles. jQuery is included inside acme.vendor and is also loaded by one component clientlib. The Dispatcher caches /etc.clientlibs for 30 days. After a release that changed JavaScript in acme.site, users continue to receive the old file for days. Author instances do not show the problem because authors run clientlibs in debug mode with separate requests.
1. Diagnose the page-weight and duplicate-library symptoms. What is the difference between `embed` and `dependencies` in this setup?
Read the worked answer
The duplicate jQuery is explained by the dependency graph, not by the browser. acme.vendor contains jQuery, and acme.site embeds acme.vendor, so jQuery is inlined into the acme.site response. A component clientlib also includes jQuery separately. Because acme.site both embeds and depends on acme.vendor, AEM can produce a combined response that includes the vendor code and still allow a separate vendor category to be loaded, depending on how the page includes categories. That is duplication.
embed means the embedded clientlib's files are aggregated into the embedding clientlib's response. dependencies means the clientlib requires another category to be present and controls ordering, but it does not merge files into one response by itself. Using both for the same category is a common source of duplication and confusing load order.
The component clientlibs also declare a dependency on acme.site, while acme.site depends on acme.components, creating a cycle. That makes ordering unpredictable and can cause repeated includes. The 2.8 MB and 14 requests are consistent with a graph that has both aggregation and separate loading of the same vendor code.
2. Propose a corrected clientlib structure. Explain which relationships you would keep and which you would remove.
Read the worked answer
I would make ownership explicit. acme.vendor owns third-party libraries, including jQuery. Component clientlibs own their component CSS/JS. acme.site owns global layout and aggregates what the page needs.
A workable structure:
acme.vendor: categoryacme.vendor, contains jQuery and other third-party files. No dependency on site code.acme.components: categoryacme.components, depends onacme.vendor, contains component-specific files.acme.site: categoryacme.site, depends onacme.componentsandacme.vendorfor ordering, and embeds the categories that should be served in one aggregated response.
I would remove the component-to-acme.site dependency, because it creates a cycle and forces global styles to load before component code that may not need them. If a component truly needs a global token or mixin, that should be in a shared dependency below both, not in the page-level aggregate. I would also remove jQuery from the component clientlib that duplicates it. Then I would measure requests and transferred bytes again; the target is one vendor response plus one site response, not 14 mixed requests.
3. What would you change about Dispatcher caching and release validation so that a future JavaScript change is visible quickly without giving up caching?
Read the worked answer
The 30-day cache is not wrong by itself, but it needs a reliable invalidation or cache-busting strategy. If clientlib URLs remain stable across releases, a 30-day TTL guarantees stale JavaScript after deployment. I would either invalidate the affected /etc.clientlibs paths as part of the release, or use a versioned clientlib path/query string so that a code change produces a new URL. The first requires disciplined flush integration; the second gives natural cache busting but must be implemented consistently.
Release validation should include:
- Confirm the published page references the new clientlib URL or that the old path was flushed.
- Check one Dispatcher directly, not only the author instance.
- Verify that
/etc.clientlibsis served through the intended proxy rules and thatallowProxyis set where required. - Compare request count and bytes before and after the change.
The judgement is to keep long cache lifetimes for stable assets while making deployment responsible for changing the URL or invalidating the path. Relying on users to hard-refresh is not a release strategy.