codycotulla
Tera Guru

Create a Script Element on a UI Page with Jelly to ensure the latest version of the script is loaded (cache busting)

Problem

I am trying to address the following problem with this post.

You have a UI Page or UI Macro that relies on a UI Script and you want to ensure that the latest version of the UI script is loaded.

For example I have a page that loads a script license_page_angular_app, so I have created the following script block.

<script></script>

The first time I load the page in the browser everything works fine.

However, if I make an update to the script, the script changes don't have any effect. This is because the first version of the script has been cached in the browser.

To get the browser to download the new version of the script, I need to make the src URL for the script block different. To do this, I add a query string to the URL with a version value, for example by making the src value license_page_angular_app.jsdbx?v=5 as in the script value below.

<script>?v=5"></script>

This works. However, it means that each time I update the script I need to update the src value on all <script> elements that load the script.

Solution

I am using the following method to solve this problem:

Instead of using static html for the script element, I use Jelly to create the script element.

To ensure that the latest version of the script is being loaded, I use the sys_mod_count value of the UI Script record in the the query string for the script element's src attribute. This way each time the UI Script is updated, the src URL changes and the browser downloads and caches the new version of the script.

Below is the Jelly code for what I have just described.

<!-- script language="javascript" src="license_page_angular_app.jsdbx?version=20"></script>

  <g:evaluate var="jvar_licensePageAngularScript" object="true">

  // load the script in this way so that when

  // I change the script, the new version of the script is downloaded.

  var loadScript = "";

  var grScript = new GlideRecord("sys_ui_script");

  grScript.addQuery("name", "license_page_angular_app");

  grScript.query();

  grScript.hasNext();

  if(grScript.next())

  {

  //The mod count (grScript.sys_mod_count) will make the URL for the script unique

  var src = "license_page_angular_app.jsdbx?v=" + grScript.sys_mod_count;

  loadScript = src;

  // Using the XML escape tags for the angle brackets that mark an HTML element

  loadScript = '&lt;script language="javascript" src="' + src + '"&gt;&lt;/script&gt;';

  }  

loadScript;

  </g:evaluate>

  <g2:no_escape>${jvar_licensePageAngularScript}</g2:no_escape>

Comments
Goran WitchDoc
ServiceNow Employee
ServiceNow Employee

Take a look at the pretty old post, but still very good and doable:
ServiceNow Style Sheets and Caching — Chris Hann



//Göran


Mathieu Cupryk
Tera Explorer

Hi Cody, can you please share your script license_page_angular_app?

Thank you.

Mathieu Cupryk
Tera Explorer

This is what i have done and seems to be working good.

 

<g2:evaluate var="jvar_stamp">
var gr = new GlideRecord('sys_ui_script');
gr.addQuery("script_name", "Name of UI Page");
gr.orderByDesc('sys_updated_on');
gr.query();
gr.next();
gr.getValue('sys_updated_on');
</g2:evaluate>

 

<g:requires name="Name of UI Page.jsdbx" params="cache=$[jvar_stamp]" />

 

 

codycotulla
Tera Guru

Hi Mathieu,

 

The license_page_angular_app was something I worked on to help learn a little bit about angular JS in ServiceNow. It was a couple companies ago, and I know longer have the code. 

 

Thanks,

 

Cody

Version history
Last update:
‎05-10-2017 03:25 PM
Updated by: