In today’s competitive business environment, a great looking website is just not enough. Focus has shifted towards page loading speeds, cross device compatibility with responsive and adaptive design patterns and also accessibility. When it comes to speed, there are many ways to improve your website’s performance. One of them is to keep resources that change infrequently cached. Using Adobe Experience Manager (AEM), you can cache most content, including images, scripts and HTML/JSP pages.
Not only can you cache these files on the dispatcher server but you can also make use of the visitor’s browser cache. If you allow files to be cached directly in the browser, the amount of load placed on the dispatcher server decreases drastically. You can inform the browser that is actually is okay for it to cache JavaScript and CSS files for a few days or maybe even weeks depending on your release cycle. But what happens when you make a change in these files before they have expired in the visitor’s browser cache? Well, then you have a problem, the user does not receive any changes unless they actually clear their browser cache, which is something that one cannot demand of their visitors.
This article explains a workaround for this issue when using AEM. The basic idea is by using Sling selectors; you can append a version number to the CSS/JavaScript files so that they will change with each release. This affects the actual name of the file so it does not matter if the browser has cached the scripts because it will look for the new file in the browser cache. Because this file does not already exist, it will fetch this new file from the server and the user will receive the latest changes.
You can create a custom Adobe Experience Manager (AEM) Link Rewriter that is based on the Apache Sling Rewriter module. This module is used for rewriting the output generated by the Sling rendering process.
Note: For more information about a Sling Rewriter, see Apache Sling Rewriter.
An Adobe CQ Link Rewriter is implemented as an OSGi bundle that contains a Java class that extends the org.apache.sling.rewriter.Transformer class. For information, see Interface Transformer.
To read this development article, click http://helpx.adobe.com/experience-manager/using/creating-link-rewrite.html.
Hi Scott, thank you for this tutorial!
You have mentioned here "you can append a version number to the CSS/JavaScript files so that they will change with each release."
Could you kindly let me know how can I do this in Geometrixx example? I created bundle as per the instruction given in this tutorial but I'm not sure how to append version number to CSS/JS using Rewriter? Thank you for your help!
Views
Replies
Total Likes
The Java logic is in the rewriteLink method. Once you deploy and activate the bundle, CQ ensures that a file is obtained from the server as opposed to using any cached version. Ojjis (our community member )can provide more details as he is the developer whom put this Java example together.
Views
Replies
Total Likes
You also might want to look at https://github.com/Adobe-Consulting-Services/acs-aem-commons/pull/49.
@Justin, Than you for this article!
I've downloaded the bundle from your POC. But I do not see the version number/modification date is appended to js/css file though the bundle is Active. PFA
Kindly let me know what I'm missing here. I appreciate your help!
Views
Replies
Total Likes
Hi Sam,
The rewriter transformer will need to be configured in your pipeline configuration. Documentation is forthcoming...
Regards,
Justin
Views
Replies
Total Likes
Did you add the correct urls for the designs in the geometrixx example.
Find out where the geometrixx example you are looking at have it's design set and add that url to the config of the rewriter as shown in the example :)
Good Luck
/Johan
Views
Replies
Total Likes
@Johan, I updated your code like this with geometrixx design path -
public CustomLinkTransformer(String version, String[] pathArray)
{
this.version = "1.0.0";
String[] myStringArray = new String[]{"/etc/designs/geometrixx"};
this.pathArray = myStringArray;
}
After I can see the difference with version number appended but page does not load properly with CSS as /etc/designs/geometrixx/static.1.0.0.css does not exists -
<link href="/etc/designs/geometrixx/static.1.0.0.css" rel="stylesheet" type="text/css">
<link href="https://forums.adobe.com/etc/designs/geometrixx.1.0.0.css" rel="stylesheet" type="text/css">
Please advice if anything else needs to be done, Thanks
Views
Replies
Total Likes
Well i didn't mean for you to change in the code. I meant that you should do that configuration in the OSGi console and then configure the ClientlibLinkRewriter there.
It is though strange that it complains about that since static.1.0.0.css would be a valid sling selector for that file.
But my suggestion would be to revert the code changes and then do the correct configuration in the OSGi console instead.
Views
Replies
Total Likes
The reason I updated code because version and path values are coming as null when I configure through OSGI.
In geometrixx example staic.css is not under clientlibs folder under /etc/designs/geometrixx which was causing issue. After I copied this file under /etc/designs/geometrixx/clientlibs and modified css.txt after it was fine. I appreciate your help!
Views
Replies
Total Likes
Hi Johan,
I have built and deployed the bundle as mentioned in the article and did below configuration changes.
1. added below properties to pipeline configuration under /apps/myApp/config/rewriter/versioned-clientlibs.
contentTypes="text/html"
enabled="true"
generatorType="htmlparser"
order="1"
serializerType="htmlwriter"
transformerTypes="[linkchecker,append-version]".
2. Added below configuration changes in osgi console
JS and CSS file path = "/etc/designs/myApp/clientLibs" and version = "1.0.0"
still version numbers are not added to my js and css files under specified path. below are the files included in page.
<link rel="stylesheet" href="https://forums.adobe.com/etc/designs/myApp/clientLib.css" type="text/css">
<script type="text/javascript" src="/etc/designs/myApp/clientLib.js"></script>
Could you please let me know if I am missing something? is version numbers added to page only in publish instance or will those be added in author instance where I am working on?
Thank you !
Views
Replies
Total Likes
Thanks Scott! Question to Ojjis, the bundle is active but when I do the view source of Geometrixx example then I don't see the version number appended.
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<meta http-equiv="keywords" content="">
<meta http-equiv="description" content="">
<script type="text/javascript" src="/etc/clientlibs/foundation/librarymanager.js"></script>
<script type="text/javascript">
CQClientLibraryManager.write([{"p":"/etc/clientlibs/foundation/jquery.js","c":[]},{"p":"/etc/clientlibs/foundation/shared.js","c":[]},{"p":"/etc/clientlibs/foundation/main.js","c":[]},{"p":"/etc/clientlibs/foundation/main.css","c":[]},{"p":"/etc/designs/mywebsite/clientlibs.js","c":[]},{"p":"/etc/designs/mywebsite/clientlibs.css","c":[]},{"p":"/etc/designs/geometrixx/clientlibs11.js","c":[]},{"p":"/etc/designs/geometrixx/clientlibs11.css","c":[]},{"p":"/etc/designs/mywebsite/clientlibs/themes/default.css","c":[]},{"p":"/etc/designs/mywebsite/clientlibs/ie6/themes/default.css","c":["ie6"]},{"p":"/etc/designs/geometrixx/clientlibs11/themes/default.css","c":[]},{"p":"/etc/designs/geometrixx/clientlibs11/ie6/themes/default.css","c":["ie6"]}],false);
</script>
<link href="https://forums.adobe.com/etc/designs/geometrixx/static.css" rel="stylesheet" type="text/css">
<link href="https://forums.adobe.com/etc/designs/geometrixx.css" rel="stylesheet" type="text/css">
<script type="text/javascript">
CQClientLibraryManager.write([{"p":"/libs/cq/ui/widgets.js","c":["!touch"]},{"p":"/libs/cq/touch/widgets.js","c":["touch"]},{"p":"/libs/cq/analytics/widgets.js","c":["!touch"]},{"p":"/libs/cq/security/widgets.js","c":["!touch"]},{"p":"/libs/cq/tagging/widgets.js","c":["!touch"]},{"p":"/libs/cq/ui/widgets/themes/default.js","c":["!touch"]},{"p":"/libs/cq/ui/widgets/themes/default.css","c":["!touch"]},{"p":"/libs/cq/touch/widgets/themes/default.css","c":["touch"]},{"p":"/libs/cq/analytics/widgets/themes/default.css","c":["!touch"]},{"p":"/libs/cq/security/widgets/themes/default.js","c":["!touch"]},{"p":"/libs/cq/security/widgets/themes/default.css","c":["!touch"]},{"p":"/libs/cq/tagging/widgets/themes/default.js","c":["!touch"]},{"p":"/libs/cq/tagging/widgets/themes/default.css","c":["!touch"]}],false);
</script>
<script type="text/javascript">
CQ.WCM.launchSidekick("/content/geometrixx/en", {
propsDialog: "/libs/foundation/components/page/dialog",
locked: false
});
</script>
<script type="text/javascript">
{
window.setTimeout(function() {
$CQ.getScript("http://localhost:4502/libs/wcm/stats/tracker.js?path=/content/geometrixx/en");
}, 1);
}
</script>
Views
Replies
Total Likes
I get the following maven compile error when trying to run this code example:
Appears to be from the following line of code:
@Property(label = "Version", description = "Version Number to be appended.", value="1.0.0")
private static final String VERSION = "version";
Views
Replies
Total Likes
I just followed that older doc and it complied --
Views
Replies
Total Likes
Intersting.
What version of the maven bundle plugin are you using? and are you using the latest AEM archetype? That seems to be whats complaining about the named variable....
Views
Replies
Total Likes
I am following the same instructions as in the doc. This was an older version of Maven as its a 5.x AEM Article.
Views
Replies
Total Likes
Views
Like
Replies