In this blog post, you’ll:

  • Learn Lightning security features to mitigate risks of malicious JavaScript code.
  • Learn about sharing JavaScript code between Aura components using shared objects and service components.
  • Learn how Winter ’19 feature “Freeze JavaScript Prototypes” influences how you choose to share JavaScript code between components.

New to Lightning Components? Check out the Lightning Component Basics module on Trailhead.

Lightning Locker Service

Since Lightning Components all render on the page together then JavaScript code in one component technically can affect–for better or for worse–other components‘ code or shared JavaScript objects, like the window object, on the page.

As early as Spring ’16, Salesforce Security introduced Lightning Locker Service to address that insecure environment and to mitigate risks of malicious JavaScript code. Locker Service particularly focuses on preventing components from affecting other components directly and restricting some DOM APIs. For example, Locker Service restricts the use of document.append() function.

Locker API Compatibility Table

Components saved with API version of 40.0 or later have Lightning Locker Service enabled and enforced automatically.

Sharing Code Securely

There are three main ways to share JavaScript code among your Lightning Components developed with the Aura programming model that I want to touch on in this blog post and how Lightning Locker Service and the Freeze JavaScript Prototypes (new in Winter ’19) setting may affect which option you choose.

  1. Sharing JavaScript Code in a Component Bundle
  2. Sharing JavaScript Code Using Shared Objects
  3. Sharing JavaScript Code Using Service Components

Sharing JavaScript Code in a Component Bundle

Component Bundle for a “Map” component

A Lightning Component bundle developed with the Aura programming model can have three JavaScript files: controller.js, helper.js, and renderer.js.

The helper file is specifically designed for sharing code within a single component bundle for use by the controller and renderer files. To access the shared code of the helper.js file, reference the helper argument passed to the functions in your controller.js and renderer.js files as shown in this gist.

Summary

If your need is to share code only within the component bundle itself, using the helper.js file is the recommended approach.

If your use case is to share code among a broader number of components, then you need a different solution than the helper.js resource, as outlined in the next approach.

Sharing JavaScript Code Using Shared Objects

Considering the restrictions Locker Service enforces on DOM APIs, it still allows developers to add custom functions and properties to shared JavaScript objects, like the window object.

Therefore, another approach to sharing code is to upload a JavaScript file as a static resource, such as a third-party library or your own custom file, that adds custom functions to shared JavaScript objects. Then, load your static resource in each of your components using the <ltng:require> tag to make the custom functions available to all your components on the page as shown in this gist.

Note that this approach relies on modifying the prototype of the window JavaScript object. We’ll come back to this when discussing the new in Winter ’19 session setting Freeze JavaScript Prototypes.

Summary

If your need is to use code from a third-party library by one or more components, loading a static resource is the recommended approach.

If your need is to use your own shared functions or to simply modularize your component code base, although the static resource approach will work, I’d recommend the next approach using component composition.

Sharing JavaScript Code Using Service Components

Another approach to share code among multiple components is “service components”. No, we’re not talking about the Service Console, but rather components purposefully developed with no visual markup and instead define <aura:method> tags to expose JavaScript functions that a containing component can call.

Rather than modify shared JavaScript objects, this approach uses component composition. This gist shows an example of a service component that adds two numbers together and returns the sum.

Adding two numbers is a trivial example. A couple examples of more practical service components that I’m fond of are:

Summary

If you find yourself copying and pasting code into multiple components, this may be a good indicator to move the common code out to one or more service components to reduce duplication and improve maintainability by following DRY principles.

Freeze JavaScript Prototypes

The Winter ’19 release introduces a new session setting Freeze JavaScript Prototypes for Improved Security and Stability. In this section, I want to point out how this may affect the way you choose to share code between components.

Per the documentation,

In JavaScript, each object has a prototype object. An object inherits methods and properties from its prototype object. Prototypes are shared between all objects of the same type. If a component author modifies a JavaScript prototype of a shared object, it can introduce unexpected behavior and potential security issues. Freezing JavaScript prototypes prevents Lightning component authors from modifying JavaScript prototypes of global objects that are shared between namespaces. This restriction enables better code separation between components and prevents malicious or inadvertent tampering of shared objects, such as the JavaScript APIs or DOM APIs.

Winter ’19 Release Notes on new “Freeze JavaScript Prototypes” Session Setting

As you may have guessed, if you enable “Freeze JavaScript Prototypes” then the approach to share code using shared objects won’t work anymore because Salesforce explicitly blocks any JavaScript’s prototype from having its properties modified.

For example, the attempt by SharedLibrary.js to define a custom function window.sum would be blocked and when your components try to call the window.sum function they’d receive an error about an attempt to use an undefined function.

Summary

With the new “Freeze JavaScript Prototypes” session setting, and given that customers may choose to enable this or require it to be enabled to meet their own security peace of mind, ISVs and customers themselves should take extra care if their approach to share code requires modifying JavaScript object prototypes. You may find that your solutions suddenly don’t work anymore.

Therefore, my recommended approach for sharing code between components is the service components approach as that avoids modifying JavaScript object prototypes to make a function available to other components.

Resources