Update January 20, 2019:

Readers, please accept my apology. My understanding at the time I first published this post in December 30, 2018 was that enabling Freeze JavaScript Prototypes would prevent developers from defining custom properties and functions on the window object. That is not correct.

The Freeze JavaScript Prototypes setting prevents developers from redefining existing properties and functions on an object’s prototype. For example, it prevents malicious code from redefining the behavior of window.open() or console.log(), but it does not prevent developers from defining their own custom properties and functions on objects, such as window.sum = function( a, b ) { return a + b; }.

I’ve corrected my statements in this post on the impact of Freeze JavaScript Prototypes setting, clarifying that the setting has far less negative impact than I original thought when customers and ISVs share JavaScript code between components using shared objects.

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.

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

What this means is that if your custom or third-party libraries rely on modifying, for example, window.prototype or Array.prototype and so on, to define special functions or polyfills or shims, then that code likely won’t work when this setting is enabled.

Let’s look at an example.

With Freeze JavaScript Prototypes disabled then the below code snippet is allowed — not recommended — but is allowed:

console.log = function( message ) {
  alert( 'I've taken over console.log, muwahaha!' );
}

With Freeze JavaScript Prototypes enabled then that code snippet would be blocked and the original behavior of console.log would be preserved.

In this example I’m just displaying an alert, but more nefarious developers might send your data to another server or hijack your session. And since any Lightning component or loaded JavaScript static resource on the page could override behaviors of standard objects, that’s why this security setting is important and you should consider enabling it. Just be aware that some of your code *might* stop working, and if so, you may need to investigate where the code is modifying prototypes and look to alternative solutions.

Resources