We often have situation where static files are changed during deployment and if static files are cached on user browser then styles are all messed up for some time.
for this. Setting like this could avoid permanent caching
You can use custom sling rewriter to append dynamic number to your static file path. For example if your static path is HOST:PORT/etc/designs/clientlibs/wemblog.js then on each production release you can change it to HOST:PORT/etc/designs/clientlibs/wemblog.<Release Number>.js
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Properties;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Service;
import org.apache.sling.rewriter.ProcessingComponentConfiguration;
import org.apache.sling.rewriter.ProcessingContext;
import org.apache.sling.rewriter.Transformer;
import org.apache.sling.rewriter.TransformerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;
@Component(metatype = true, immediate = true, label = "Link Transformer", description = "Appends version number to the js and css files under specified paths")
@Service
@Properties({ @Property(name = "pipeline.type", value = "append-version", propertyPrivate = true) })
public class ClientlibLinkTransformerFactory implements TransformerFactory {
@Property(label = "JS and CSS file path", cardinality = Integer.MAX_VALUE, description = "Path to the JS and CSS files", value = "[/etc/designs/SOMEPATH/clientlibs]")
private static final String PATH = "path";
@Property(label = "Version", description = "Version Number to be appended.")
private static final String VERSION = "version";
private static final String HTML_TAG_SCRIPT = "script";
private static final String HTML_TAG_LINK = "link";
private static final String HTML_ATTRIBUTE_SRC = "src";
private static final String HTML_ATTRIBUTE_HREF = "href";
private static final String JS_EXTENTION = ".js";
private static final String CSS_EXTENTION = ".css";
private static final String SELECTOR_SEPARATOR = ".";
private static final Logger log = LoggerFactory.getLogger(ClientlibLinkTransformerFactory.class);
private String version = "";
private String[] pathArray;
@Activate
protected final void activate(final Map<String, Object> config) {
this.version = (String) config.get(VERSION);
this.pathArray = (String[]) config.get(PATH);
}
public Transformer createTransformer() {
return new ClientlibLinkTransformer();
}
private boolean shouldAppendVersion() {
return StringUtils.isNotEmpty(this.version) && this.pathArray != null && this.pathArray.length > 0;
}
private Attributes rewriteLink(Attributes atts, String attrNameToLookFor, String fileExtension) {
boolean rewriteComplete = false;
AttributesImpl newAttrs = new AttributesImpl(atts);
int length = newAttrs.getLength();
for (int i = 0; i < length; i++) {
String attributeName = newAttrs.getLocalName(i);
if (attrNameToLookFor.equalsIgnoreCase(attributeName)) {
String originalValue = newAttrs.getValue(i);
if (StringUtils.isNotEmpty(originalValue)) {
for (String pathPrefix : pathArray) {
if (StringUtils.isNotEmpty(pathPrefix) && originalValue.indexOf(pathPrefix) != -1) {
int index = originalValue.lastIndexOf(fileExtension);
if (index != -1) {
newAttrs.setValue(i, originalValue.substring(0, index) + SELECTOR_SEPARATOR
+ this.version + fileExtension);
rewriteComplete = true;
break;
}
}
}
if (rewriteComplete) {
break;
}
}
}
}
return newAttrs;
}
private class ClientlibLinkTransformer implements Transformer {
private ContentHandler contentHandler;
public void characters(char[] ch, int start, int length) throws SAXException {
contentHandler.characters(ch, start, length);
}
public void dispose() {
// TODO Auto-generated method stub
}
public void endDocument() throws SAXException {
contentHandler.endDocument();
}
public void endElement(String uri, String localName, String qName) throws SAXException {
contentHandler.endElement(uri, localName, qName);
}
public void endPrefixMapping(String prefix) throws SAXException {
contentHandler.endPrefixMapping(prefix);
}
public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {
contentHandler.ignorableWhitespace(ch, start, length);
}
public void init(ProcessingContext context, ProcessingComponentConfiguration config) throws IOException {
// TODO Auto-generated method stub
}
public void processingInstruction(String target, String data) throws SAXException {
contentHandler.processingInstruction(target, data);
}
public void setContentHandler(ContentHandler handler) {
this.contentHandler = handler;
}
public void setDocumentLocator(Locator locator) {
contentHandler.setDocumentLocator(locator);
}
public void skippedEntity(String name) throws SAXException {
contentHandler.skippedEntity(name);
}
public void startDocument() throws SAXException {
contentHandler.startDocument();
}
public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
if (shouldAppendVersion() && HTML_TAG_SCRIPT.equalsIgnoreCase(localName)) {
contentHandler.startElement(uri, localName, qName, rewriteLink(atts, HTML_ATTRIBUTE_SRC, JS_EXTENTION));
} else if (shouldAppendVersion() && HTML_TAG_LINK.equalsIgnoreCase(localName)) {
contentHandler.startElement(uri, localName, qName,
rewriteLink(atts, HTML_ATTRIBUTE_HREF, CSS_EXTENTION));
} else {
contentHandler.startElement(uri, localName, qName, atts);
}
}
public void startPrefixMapping(String prefix, String uri) throws SAXException {
contentHandler.startPrefixMapping(prefix, uri);
}
}
}
You can dynamically update version number to get fresh static file.