Skip to main content
Version: v4.5

Node.js Apps Setup

As mentioned in Platform API, we publish ES modules to be used in both Node.js Apps and browser Apps.

Please make sure you have a Node.js LTS or any version after 13.2.0 so the dynamic import feature is supported. Here’s a good resource on using ES modules in Node.js: Using ES modules in Node.js - LogRocket Blog

Some steps to make sure your app can use dynamic import feature provided by IafScriptEngine:

  1. Add the following line to your package.json:
  “type”: “module”
  1. Because fetch is only native in the browser world, we need to include isomorphic-fetch in package.json and import like the following:
  import * as isomorphicFetch from 'isomorphic-fetch';
  1. Similar with FormData:
import * as FormData from 'isomorphic-form-data';
  1. Add the following method and call this method at the beginning of the app initialization:
function addFetchToGlobalConfig() {    if (global) {        if (!global.fetch) {                global.fetch = isomorphicFetch.fetch;        }        if (!global.FormData) {                global.FormData = FormData;        }    }}
  1. Replace any “require” syntax with import statements.
  2. Similarly, replace module.exports with export.
  3. If you have Jest test suite, make sure to upgrade/add jest packages and related including jest, @babel/preset-env, @jest/globals, babel-jest to the latest, sometimes you might even need core-js, btoa and regenerator-runtime.
  4. Use ES modules whenever possible. For example, we use lodash-es instead of lodash.

Node.js App Sample#

Below is an example of how to write server side code and use IafScriptEngine.dynamicImport to load user-defined scripts to get user groups in the project. Again, dynamic import via URL is not allowed in Node.js, but you can use an experiment loader to do that. This example uses vm2 just to show you how to sandbox the scripts on the server side. Directly running the scripts in Node.js w/o using vm2 will work as well.

To run the script, do:

node --experimental-loader ./https-loader.mjs userGroups.mjs 

userGroups.mjs:#

//userGroups.mjs//use node-fetch as fetch is not available in Node.jsimport * as isomorphicFetch from 'isomorphic-fetch';import {NodeVM} from 'vm2'import * as PlatformApi from "@dtplatform/platform-api"
const endPointConfig = {    itemServiceOrigin: 'https://general-dev.company.com',    passportServiceOrigin: 'https://general-dev.company.com',    fileServiceOrigin: 'https://general-dev.company.com',    datasourceServiceOrigin: 'https://general-dev.company.com'  };
const vm = new NodeVM({     sandbox: {        PlatformApi: PlatformApi,        endPointConfig: endPointConfig    }});    let result = vm.run(`
async function getUserGroups(ctx){    try{        PlatformApi.IafSession.setConfig(endPointConfig)        //criteria and project are pre-defined here        let module = await PlatformApi.IafScriptEngine.dynamicImport(criteria, ctx)        let UserGroupScripts = module.default        await PlatformApi.IafProj.switchProject(project._id, ctx)        let userGroups = await UserGroupScripts.getUserGroups(PlatformApi, ctx)        console.log(userGroups)        return userGroups    }catch(e){        console.log(e)    }}
getUserGroups({_namespaces:['xxxxxxx''], authToken: 'very long string'})`)
console.log(result)

https-loader.mjs:#

// https-loader.mjsimport * as isomorphicFetch from 'isomorphic-fetch';
const getHTTPSource = async (url, resolve, reject) => {    try {        let res = await fetch(url);        let data = await res.text();        resolve({ source: data });    } catch (err) {        reject(err);    }}
export function resolve(specifier, context, defaultResolve) {    const { parentURL = null } = context;
    // Normally Node.js would error on specifiers starting with 'https://' or 'http://', so    // this hook intercepts them and converts them into absolute URLs to be    // passed along to the later hooks below.    if (specifier.startsWith('https://') || specifier.startsWith('http://')) {        return {            url: specifier        };    } else if (parentURL && ( parentURL.startsWith('https://') || parentURL.startsWith('http://') )) {        return {            url: new URL(specifier, parentURL).href        };    }
    // Let Node.js handle all other specifiers.    return defaultResolve(specifier, context, defaultResolve);}
export function getFormat(url, context, defaultGetFormat) {    // This loader assumes all network-provided JavaScript is ES module code.    if (url.startsWith('https://') || url.startsWith('http://')) {        return {            format: 'module'        };    }
    // Let Node.js handle all other URLs.    return defaultGetFormat(url, context, defaultGetFormat);}
export function getSource(url, context, defaultGetSource) {    // For HTTP(S) protocol, fetch url & return the response text data    if (url.startsWith('https://') || url.startsWith('http://')) {        return new Promise(async (resolve, reject) => getHTTPSource(url, resolve, reject));    }
    // Let Node.js handle all other URLs.    return defaultGetSource(url, context, defaultGetSource);}