Using Custom JavaScript Modules as Static Resources in Salesforce Orgs | by Lynn Zheng | Towards Data Science

This tutorial will walk you through integrating your custom JavaScript modules with Salesforce Lightning Web Components and use them in Salesforce Orgs.
A Salesforce org is a customer-facing platform that contains Salesforce data.
A lightning web component is essentially a Web Component that uses Salesforce-branded styles and encapsulates Salesforce data.
What you will need:
A Trailhead account which allows you to create a Trailhead playground/test org
Salesforce Developer Experience (SFDX) command-line client
Visual Studio Code
If you haven’t yet set up the full Salesforce Developer Experience (SFDX) environment, go to Trailhead, sign up, and complete the Quick Start: Lightning Web Components Trail. This will set up the entire toolkit we need for this tutorial and should take no more than 20 minutes.
If you are a Visualforce or an Aura developer who has set up SFDX but aren’t familiar with LWC, I’d recommend you to work through the last module of the Quick Start: LWC Trail to create a HelloWorld LWC.
If you are otherwise already familiar with SFDX and LWC, go ahead and create a simple HelloWorld LWC. The LWC doesn’t have to be anything more than <div>Hello World</div> .
Wherever you are coming from, you should end up with an org page that contains a custom LWC with files helloWorld.html, helloWorld.js, and helloWorld.js-meta.xml.
Add a button to the custom LWC using thelightning-button tag. Its label attribute contains the text it displays. Its onclick attribute should point to an event handler called clickHandler .
In helloWorld.html, add the HTML for the button:
<lightning-button label=”Say Hello in the JS Console” onclick={clickHandler}></lightning-button>
In helloWorld.js, implement the clickHandler method:
clickHandler() {    console.log('hello from helloWorld.js');}
Open the default org page (in Visual Studio Code, Command + Shift + P, SFDX: Open Default Org), open the web console, click the button, and we should see the console log.
In case the org doesn’t automatically refresh, click on the gear icon on the top right hand of the page, go to Page Setup, Refresh the current page, and Save.
Create two files under force-app/main/default/staticresources, helloModule.js, and helloModule.resource-meta.xml.
To use a custom JavaScript file as a static resource, we need to wrap it in an Immediately Invoked Function Expression (IIFE).
IIFE in helloModule.js:
(function() {    function sayHello() {        console.log('hello from helloModule.js');    }    // this makes the sayHello function available in the window     namespace    // so we can call window.sayHello from any LWC JS file    window.sayHello = sayHello;})();
In helloModule.resource-meta.xml, we specify the resource content type and cache-control property:
<?xml version="1.0" encoding="UTF-8"?><StaticResource xmlns="http://soap.sforce.com/2006/04/metadata" fqn="helloWorld">  <cacheControl>Private</cacheControl>  <contentType>application/javascript</contentType></StaticResource>
Deploy force-app/main/default/staticresources to the org. On the org page, go to Setup and search for Static Resources. There should be a resource named helloModule, with type application/javascript and private cache control.
In helloWorld.js, add the import for the static resource and for the method that loads the static resource:
import SAY_HELLO from '@salesforce/resourceUrl/helloModule';import { loadScript } from 'lightning/platformResourceLoader';
Then implement a callback that runs when the LWC is rendered on the page:
renderedCallback() {    loadScript(this, SAY_HELLO)    .then(() => console.log('Loaded sayHello'))    .catch(error => console.log(error));}
Deploy this LWC to org. Refresh the org page and we should see the console log indicating that the helloModule static resource has been successfully loaded.
Now that the resource is successfully loaded, we are able to use the function sayHello in the LWC. In helloWorld.js, update the button click handler to call window.sayHello:
clickHandler() {    console.log('hello from helloWorld.js');    window.sayHello();}
Deploy to org, refresh, click on the button, and we should see the log from helloModule printed to the console.
Because of the default security settings of Salesforce org, if our JavaScript function needs to call a non-Salesforce, third-party API, we need to list those sites as CSP (Content-Sharing Policy) Trusted Sites. We will use JSONPlaceholder as an example. Go to Setup and search for CSP Trusted Sites. Add a new trusted site as follows: (Note that Salesforce won’t accept a URL that ends with a forward slash, i.e., https://mysite.com works but https://mysite.com/ doesn’t.)
CSP might take two to five minutes to become effective. In the meantime, add a function to helloModule.js (still inside the IFFE) and also expose it to the window namespace:
function retrieveData(dataId) {    fetch('https://jsonplaceholder.typicode.com/todos/' + dataId)    .then(response => response.json())    .then(json => console.log(json));}window.retrieveData = retrieveData;
Update clickHandler in helloWorld.js to use window.retrieveData with a parameter:
clickHandler() {    console.log('hello from helloWorld.js');    window.sayHello();    for (let i = 1; i < 4; i++) {        window.retrieveData(i);    }}
Deploy, refresh, if there’s no CSP error (which means that CSP isn’t yet in effect), we should be able to see some JSON data fetched from a third-party API in the console log.
The complete files are as follows:
helloWorld.html:
<template>  <lightning-card title="HelloWorld" icon-name="custom:custom14">    <div class="slds-m-around_medium">      <p>Hello, {greeting}!</p>      <lightning-input label="Name" value={greeting} onchange={changeHandler}></lightning-input>      <lightning-button label="Say Hello in the JS Console" onclick={clickHandler}></lightning-button>    </div>  </lightning-card></template>
helloWorld.js:
import { LightningElement } from 'lwc';import SAY_HELLO from '@salesforce/resourceUrl/helloModule';import { loadScript } from 'lightning/platformResourceLoader';export default class HelloWorld extends LightningElement {    greeting = 'World';    changeHandler(event) {        this.greeting = event.target.value;    }    clickHandler() {        console.log('hello from helloWorld.js');        window.sayHello();        for (let i = 1; i < 4; i++) {            window.retrieveData(i);        }    }    renderedCallback() {        loadScript(this, SAY_HELLO)        .then(() => console.log('Loaded sayHello'))        .catch(error => console.log(error));    }}
helloModule.js:
(function() {    function sayHello() {        console.log('hello from helloModule.js');    }    function retrieveData(dataId) {        fetch('https://jsonplaceholder.typicode.com/todos/' + dataId)        .then(response => response.json())        .then(json => console.log(json));    }    // this makes the sayHello function available in the window namespace    // so we can call window.sayHello from any LWC JS file    window.sayHello = sayHello;    window.retrieveData = retrieveData;})();
For more resources, check out Trailhead and Salesforce’s Official Documentation for Developers.