Working with Server Side JavaScript

Introduction

You can execute server-side JavaScript (SSJS) in components and design parse files by including the runat="server" attribute when using a <script> tag. For example:

<script runat="server">
  print('<h1>%asset_name%</h1>');
</script>

You can also execute a JavaScript file by sourcing it using the src attribute, for example:

<script runat="server" src="./?a=XXXX"></script>

This functionality is similar to that of the JavaScript processing field on the REST resource JavaScript asset.

When used in components, SSJS is not processed at the time of the processing of the component content. Instead, it is processed at the global level along with any global keyword replacements.

Global variables

You can set global JavaScript variables which other components can access in the page processing.

For example, if you have a nested standard page at the top of my design parse file code that has the following SSJS code:

<script runat="server">
  var userName = '%globals_user_attribute_username%';
</script>

You can then access the same global variable at any other point in the Matrix page generation, either in another component or in the design parse file code:

<script runat="server">
  print(userName);
</script>

Attributes

You can pass additional attributes into the <script> tag for the server-side functionality, including:

Runat="server"

Enables the JavaScript code within the tag to run server-side.

Evalkeywords="post"

By default, keywords are evaluated before the JavaScript is processed. Adding this attribute will make the keywords evaluate after the JavaScript has been processed.

This only applies to global keywords. In-context asset-specific keywords such as %asset_name% will always need to be evaluated in the context of where they are printed.
Log="log_prefix"

Adding this attribute will log any output from the JavaScript as an entry into the Matrix system log. The value of the log attribute will prefix the messages that are printed through the JavaScript print() function.

Performance mode

You can see metrics of the performance of the server-side JavaScript within performance mode. For example:

performance mode ssjs

Three entries are shown under the asset the JavaScript block is executed under and includes:

Process server-side JavaScript "pre" keywords

Time to process keyword replacements before the JavaScript has been processed.

Process server-side JavaScript

Time to process the JavaScript code.

Process server-side JavaScript "post" keywords

Time to process keyword replacements after the JavaScript has been processed.

Disabling SSJS

You can disable all JavaScript from running on the server using the runat="server" method by adding the following query string parameter to the URL:

?SQ_DISABLE_SERVER_JS

The JavaScript in the component will print within the HTML source and execute client-side as standard JavaScript. This allows debugging of the JavaScript within the source code of the page.

You need to have write access to the component for this query string to take effect.

Viewing SSJS

If you have write access to an asset, you can append ?SQ_VIEW_SERVER_JS to the URL when previewing it on the frontend to see a complete output of the JavaScript code that was sent to the JavaScript engine in Matrix.

This is useful if you are getting JavaScript errors on the frontend that relate to a specific line number in your code, as you will be able to track down exactly which line the error is referring to.

For example, if you received an error similar to the one in the example below. The error points to line 20 in the JavaScript code.

server side js error

Viewing the frontend page with ?SQ_VIEW_SERVER_JS appended to the URL, you can see to which line the error refers. You can also use JavaScript comments to help indicate from which specific asset each JavaScript block is coming.

server side js code

Processing order

It is essential to understand how Matrix will process keywords and SSJS and the order in which these get evaluated.

Essential rules to remember for keyword replacements:

  • Asset keywords always get replaced in context (that is, %asset_name% in standard page and asset listing type format components and %frontend_asset% keywords).

  • Global keywords get replaced further up but before all SSJS by default.

  • Global keywords in SSJS with evalkeywords="post" attribute get replaced after all SSJS.

Matrix also replaces global keywords and processes SSJS in two separate places:

  1. At the globals level

  2. In the design parse file.

Therefore, the Matrix processing order of these are as follows:

  1. Components - asset & frontend asset keywords.

  2. All global keywords.

  3. All SSJS.

  4. All global keywords in SSJS with evalkeywords="post".

  5. Parse file - Global keywords.

  6. Parse file - SSJS.

  7. Parse file - Global keywords in SSJS with evalkeywords="post".

run_SSJS keyword modifier

Sometimes you might want to execute SSJS code within the contents of an asset earlier than at the global level. For example, when using the contents of an asset in a trigger action.

To do this, you can use the ^run_SSJS keyword modifier to execute any SSJS code found within the contents of a keyword as a separate processing thread. For example:

%globals_asset_contents_raw:1234^run_ssjs%

Examples

This section will show you some examples of how you can use SSJS and the different outcomes you will get depending on what keywords you use and how you print the code to the frontend.

Basic example

This example will conditionally print a <metadata> SEO-based section tag based on the value of the current frontend URL the user is viewing.

<script runat="server">
  //Create a variable with the current frontend asset's URL
  var frontendURL = '%frontend_asset_url%';
  //Create a variable for the section string
  var section = '';
  //Set the section string based on the section where the current URL is located under
  if(frontendURL.indexOf('/manuals') > 0){
    section = 'Manuals';
  }else if(frontendURL.indexOf('/tutorials') > 0){
    section = 'Tutorials';
  }else if(frontendURL.indexOf('/news') > 0){
    section = 'News';
  }
  //Print a metadata tag for the current section if it is not empty
  if(section != ''){
    print('<meta property="article:section" content="' + section + '"/>');
  }
</script>

This SSJS code could then be placed somewhere inside the <head> tag of the page design.

This example takes a list of assets from a related asset metadata field and loops through each one to print information about each asset in an unordered list, similar to what you might use an asset listing for.

<script runat="server">
  //Store array of assets from metadata field into a variable
  var assets = %asset_metadata_related^json_decode^as_asset:asset_name_linked^empty:[]%;
  //Only run if there are actually any assets in the array
  if(assets.length > 0){
    print('<ul>');
    //For each asset, print the value
    assets.forEach(function(asset){
      print('<li>'+ asset +'</li>');
    });
    print('</ul>');
  }
</script>

The critical thing to note is that the keyword will be replaced before the JavaScript is processed. So the JavaScript will see an array of data directly assigned to the assets variable, rather than a keyword string.