JavaScript Modules in MarkLogic 10
In this 3-part blog series, we’ll be reviewing over some of the new features of MarkLogic 10, such as:
- The addition of JavaScript Modules, also known as MJS.
- V8 Engine upgrade from version 5.3 to version 6.7. This is the actual motor that ‘powers’ JavaScript in MarkLogic.
- Additional features from the ECMAScript 2015 JavaScript standard have been added. Go to ECMA International to find out what you can do with ECMAScript 2015.
In this first blog of the series, we’ll discuss destructuring assignment and compare the differences between JavaScript Modules (MJS) and Server-side JavaScript (SJS) by working through some examples. We’ll also discuss some of the advantages of upgrading to MarkLogic 10.
In the next blog, we’ll discuss in detail about the new API’s the V8 Engine upgrade comes with. And after that, we will discuss another piece of functionality that was included in the upgrade, Object Rest and Spread Properties, and how they can be used in your Data Hub code. So if you’d like to see all the new things you can do with JavaScript in MarkLogic 10, stick around!
Now let’s get started with an introduction to JavaScript Modules.
Destructuring Assignment
Let’s jump in with some typical MarkLogic 9 code:
const validator = require("/lib/validator.sjs") validator.isValidZipCode("10001") validator.isValidPostCode("6025")
In this example, you require the "/lib/validator.sjs"
SJS script and assign that to the validator variable. Then, you can use the functions from the "/lib/validator.sjs"
SJS script in your code by referencing the validator variable. Although this seems simple enough, with destructuring assignment, the syntax becomes even more concise:
const { isValidZipCode, isValidPostCode } = require("/lib/validator.sjs") isValidZipCode("10001") isValidPostCode("6025")
Now, you can use the functions without having to specify the validator prefix. And this gets even more concise again when you use MJS modules:
import { isValidZipCode, isValidPostCode } from "/lib/validator.mjs"; isValidZipCode("10001") isValidPostCode("6025")
Using the new syntax, you simply import
the functions you want to use. In this case, we want the functions isValidZipCode
and isValidPostCode
, imported from the file "/lib/validator.mjs"
. Now, you can use the functions without having to specify the validator prefix.
SJS vs MJS
Now let’s take a look at what the differences are in the actual script. For example, your typical SJS script might look something like this:
function isValidZipCode(code) {/*...*/} function isValidPostCode(code) {/*...*/} module.exports = { isValidZipCode: isValidZipCode, isValidPostCode: isValidPostCode };
So we have functions, isValidZipCode(code)
and isValidPostCode(code)
, and a module.exports
declaration where you declare what you actually want to export for use by the client.
If we look at MJS, the code is actually quite similar, but much more concise for declaring the exports:
function isValidZipCode(code) {/*...*/} function isValidPostCode(code) {/*...*/} export { isValidZipCode, isValidPostCode };
Advantages of MJS
One of the main advantages of going from using SJS to MJS is that your code executes faster. This is because SJS scripts are loaded for every single request, whereas MJS modules are loaded once into a global module cache and shared between requests, thus improving performance.
In other words, SJS scripts cannot be shared across multiple MarkLogic requests. Once you load an SJS script, it’s unique to that request, and you can’t actually share it with multiple requests. If a request includes a require in the script, it has to be loaded every time.
However, with MJS, scripts can be shared by multiple MarkLogic requests. So if you have code that’s executed repeatedly, it should execute faster as you don’t have to load the code with each request.
How to Upgrade from SJS to MJS
Firstly, you need to rename the extension from .sjs
to .mjs
. Then, you need to change your module exports from the SJS syntax from:
module.exports = { isValidZipCode: isValidZipCode, };
to the more concise MJS code here:
export { isValidZipCode }
Then, convert the SJS require
step from:
const validator = require("/lib/validator.sjs")
to use the import
declaration in your MJS:
import * as validator = from "/lib/validator.sjs";
Alternatively, you can specify exactly which functions you want imported, e.g.:
import { isValidZipCode, isValidPostCode } from "/lib/validator.mjs";
Data Services Changes Required
If you’re using Data Services, note that it generates the code for you and you may need to do some tweaking. For instance, if you had the following in your data service .sjs
file for an input parameter param1:
var param1;
You would need to change it to the following in your .mjs
file:
const param1 = external.param1
Also if you have already generated the Java client code, you will need to change it. For example, if you had a search function (search.sjs
) in SJS, you’ll need to point it to the new MJS file (search.mjs
).
@Override public reader search(String q, ...) { return BaseProxy.JsonDocumentType.ToReader(baseProxy.request("search.sjs, ...)
@Override public reader search(String q, ...) { return BaseProxy.JsonDocumentType.ToReader(baseProxy.request("search.mjs, ...)
Dynamic Module Loading Impact
One thing to be aware of is that you cannot load JavaScript modules dynamically in MarkLogic. For example, you can do the following in SJS:
let lib = someCondition() ? require("/lib/foo.sjs") : require("/lib/bar.sjs")
But you cannot do the equivalent using MJS in MarkLogic.
V8 JavaScript Engine Performance Improvement
All-in-all, one of the best reasons to move to MarkLogic 10 as soon as you can is that the actual engine itself (V8) has seen an improvement in performance, particularly for the most commonly used functionality (e.g. String and Array operations). With this increased engine performance, codebases that make heavy use of JavaScript should experience a performance gain.
Next Steps
We just walked through destructuring assignment, the differences between SJS and MJS, and found out why upgrading to MarkLogic 10 and using MJS can speed up the execution of your code. You can read up more about Server-Side JavaScript in MarkLogic in our JavaScript Reference Guide.
In the next blog in our series, we will go over the details behind the V8 Engine Upgrade with MarkLogic 10 and some of the new functionality that comes with the new APIs. After that, we’ll walk through the new Rest and Spread Properties functionality.
Dermot Smyth
Dermot is a Senior Technologist with over 15 years of experience architecting, developing and delivering software using state-of-the-art technologies. Prior to joining MarkLogic, he worked internationally in a broad range of industries including Investment Banking, Insurance, Energy and Tertiary Education.
Originally from Australia, he now lives in Paris and is enjoying working his way through all the different types of French cheese (over 400!)