CDN Considerations documentation for the dotCMS Content Management System

Inodes

Whenever a new version of site, page, content, file or asset is published in dotCMS, dotCMS creates a new inode id for that version. This inode is a globally unique UUID that is perfect to include when you reference the asset's url to perform automatic and free cache invalidations.

Sitewide

In your templates and container code, it is possible to use your Site/Host inode or a field value in the Host content type as a “nonce”, a meaningless value that you add to your existing urls that can be updated and there by invalidate any calls to those urls. For example, you could reference a css/sass file and append the parameter ?v=$host.inode. When you want to invalidate your global files, all you need to do is save and activate a new version of your host/site. Doing this will create a new $host.inode and invalidate any paths that are including it as a parameter.

<link rel="stylesheet" href="/application/themes/dotcms/css/main.dotsass?v=$host.inode">

Images and Assets

Use inodes to reference static file assets within dotCMS VTL so dotCMS will automatically use a cache-busting URL for included CSS, javascript, image, or other media or asset files. The URL for these files will change every time the file is edited.

To include a single file use webapi.getAsssetInode:

<script src=”dA/${webapi.getAssetInode('/application/themes/dotcms/css/vendor/jquery.fancybox.min.css')}/jquery.fancybox.min.css”></script>

This produces:

<script src="/dA/7e39a735-47d6-443b-835f-9a7387c54117/script.js"></script>

Or include all javascript files in a directory with dotcontent.pull:

#set($jsThemePath = ${dotTheme.path} + "js/")
#foreach($jsFile in $dotcontent.pull(
        "+contentType:FileAsset
        +(conhost:${host.identifier} conhost:SYSTEM_HOST)
        +FileAsset.fileName_dotraw:*.js
        +parentpath:${jsThemePath}",
        10,"score,modDate desc")
    )
    <script src="${jsFile.shortyUrlInode}"></script>
#end

This produces:

<script src="/dA/7e39a73547/script.js"></script>
<script src="/dA/dd32bda0f9/core.min.js"></script>

For more information take a look at the content version documentation or displaying images with binary image fields documentation

Velocity Scriptlet for Invalidations {velocity-scriptlet-for-invalidations}

The script below is an example script of that shows how you can use Velocity to perform cache invalidations when a piece of content is changed, published or removed. This code is intended as an example and can be encapsulated in a .vtl and called in a workflow task using the Velocity Scripting Actionlet whenever a piece of content is published. It figures out what URLs are assoicated with the piece of content, of whether the content is a page, a file, a URLMap or a dotAsset and invalidates the urls associated with the give piece of content.

#set($baseDomain = "https://dotcms.cdn.net")
#set($AccessKey = "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXXXXXX")
#set($urls = [])

#set($id=$webapi.findIdentifierById("$content.identifier"))
#if($!content.contentObject.isFileAsset() || $content.isFileAsset())
    $!logger.info("invalidating a fileAsset $id.path")
    #set($x = $urls.add("$id.path"))
#elseif($!content.contentObject.isHTMLPage() || $content.isHTMLPage())
    $!logger.info("invalidating a page: $id.path")
    #set($x = $urls.add("$id.path"))
#elseif($urls.size()==0)
    #set($myContent=$dotcontent.find("$content.identifier"))
    #if($!content.contentObject.isDotAsset() || $content.isDotAsset())
        $!logger.info("invalidating a dotAsset: $myContent.getShortyUrl()")
        #set($x = $urls.add("$myContent.getShortyUrl()"))
        #set($x = $urls.add("$myContent.getShortyUrlInode()"))
    #elseif($!myContent.urlMap)
        $!logger.info("invalidating a urlMap: $myContent.urlMap")
        #set($x = $urls.add("$myContent.urlMap"))
    #end
#end

#set($headers = {})
#set($x = $headers.put("Content-Type", "application/json"))
#set($x = $headers.put("AccessKey", "$AccessKey"))

#foreach($url in $urls)
    #set($invadateUrl = "https://mycdn.com/api/purge?url=${baseDomain}${url}")
    $!logger.info("invadateUrl: $invadateUrl")
    #set($x = $json.post($invadateUrl, $headers, {}))
#end