2017-02-16

Regardless of the language, framework, or platform you use, modern applications are built by assembling discrete and composable components. On the Salesforce platform, the application composition infrastructure is provided by the Lightning Component Framework. That’s how the Salesforce Apps (Sales Cloud, Service Cloud, etc) are built, and that’s also how you can extend and customize these apps with your own components, or create completely new apps.

The components you assemble can come from different sources. For example, you can build an application (or a page) by assembling Salesforce components, third-party components, and your own components. Components can be built entirely from scratch or by leveraging third-party libraries. In this article, we discuss the different types of libraries you may want to use in a Lightning Component, and we compare two isolation mechanisms (LockerService and the Lightning Container Component) that allow you to use them securely and avoid security exploits.

Which Library Do You Need?

Third-party libraries usually fall in one of the following categories:

DOM manipulation libraries (jQuery, etc)

Specialized utility libraries (moment.js, numeral.js, etc)

UI libraries (Bootstrap, jQuery UI, etc)

Data visualization libraries (D3, Chart.js, Leaflet, etc)

MVC frameworks (React, Angular, etc)

Before we look at how you can use a third-party library in a Lightning Component, it’s useful to ask yourself why you are using it, and if you really need it. In some cases the answer will be a resounding yes: nobody wants to reinvent a data visualization library like D3 or a mapping library like Leaflet. In other cases the answer will be less clear. Let’s take a closer look at DOM manipulation libraries, UI libraries, and MVC frameworks in particular.

DOM Manipulation Libraries

JavaScript has come a long way in recent years. Many DOM manipulation utilities we couldn’t live without in libraries like jQuery are now standard in the language. Modern frameworks like the Lightning Component Framework also provide abstractions that make jQuery less relevant. For example, let’s say you have to set the value of a score input field to 100.

Using jQuery, you would:

Assign a unique id to the input element

Use a jQuery selector to find the input element in the DOM

Assign the value to that DOM element

Using the Lightning Component Framework, you would:

Declare a score attribute

Bind the input field to the score attribute

Set the value of the score attribute: the bound input field will automatically display the new value.

In the Lightning approach, the model and the view are decoupled: your code doesn’t have to reach into the DOM. This leads to more robust and more maintainable code. Avoiding direct DOM manipulation is a best practice in the Lightning Component Framework (like in most modern frameworks), and you might just discover that you no longer need your DOM manipulation library.

UI Libraries

You may also want to reconsider the use of UI libraries like Bootstrap and jQuery UI. Although these libraries provide useful components, they have their own UI identity that can clash with the Lightning Experience identity. The Base Lightning Components and the Lightning Design System offer similar capabilities while providing a consistent user experience.

MVC Frameworks

At a high level, libraries like React and AngularJS have the same focus as the Lightning Component Framework: They provide code organization and utilities to create components. If you are looking for a component framework to develop applications on the Salesforce platform, you should use the Lightning Component Framework because it’s tightly integrated with the platform. But you can also use other frameworks if you so desire. All you have to do is choose the isolation mechanism (LockerService or Lightning Container Component) that works with your framework to avoid security exploits (see below).

Avoiding Security Exploits

To avoid security exploits, an application composition framework should provide the right level of isolation between components. For example, an untrusted component shouldn’t be able to gain access to the part of the DOM owned by another component. Without the right level of isolation, a vulnerability in one component can provide access to sensitive data in other components and jeopardize the security of the entire system. Just like breaking into one apartment would provide access to all the apartments in the building if each apartment didn’t have its own secured door. Each component you use in an application is an attack vector, and as a corollary, each library you use in any component is an attack vector as well. The Lightning Component Framework comes with two isolation mechanisms: LockerService and the Lightning Container Component (in Developer Preview in Spring ’17).

LockerService Isolation

LockerService is the primary and preferred isolation mechanism for the Lightning Component Framework. LockerService wraps standard objects like window, document, and element inside a secure version of these objects (SecureWindow, SecureDocument and SecureElement) as a way to control access to APIs and regions of the DOM. When components are loaded, they are provided with the secure wrappers (secureWindow and secureDocument) in lieu of the standard objects (window and document). When a component invokes a method on the document or window object, the secure wrapper can apply appropriate security restrictions. For example, access to the DOM of another component will be:

Granted if the other component is in the same namespace.

Denied if the other component is in a different namespace.

In addition to providing a sophisticated namespace-based access control mechanism, LockerService enforces a series of rules to further avoid security exploits:

JavaScript ES5 strict mode is automatically enabled. Libraries that do not support strict mode will not work with LockerService.

Content Security Policy (CSP). unsafe-eval and unsafe-inline are disallowed. Libraries using eval() or inline JavaScript code execution will not work with LockerService.

The rules enforced by LockerService are recognized as industry best practices. However some libraries may not yet work with these restrictions enabled. In that case, we recommend you ask the library author to support strict mode and CSP. In the meantime, you can use the alternative Lightning Container Component isolation described below.

LockerService Advantages

No iframe. Components live in the same DOM (better performance)

Straightforward, natural communication between components

Cohesive UI

Eliminates DOM scraping vulnerabilities

Mitigates the impact of developer mistakes such as the lack of proper escaping

Cross-site scripting (XSS) and template injection are no longer possible

Eliminate server-side action invocation/spoofing

LockerService Limitations

Non-compliant libraries will not work with LockerService

Here is a non- exhaustive list of libraries that are known to work with LockerService:

Library

Version

React

0.14.8

ChartJS

2.1.4

D3

4.4.0

Leaflet

0.7.7 and 1.0.2

RxJS

Latest as of 12/5/16

Numeral.js

2.1.4

Underscore.js

1.8.3

FullCalendar

3.1.0

Gauge.js

1.2.1

jQuery

2.2.2 and 2.2.4

jQuery UI

1.11.4

DataTables

1.10.12

Select2

4.0.3

Disclaimer: The versions above are known to work. We can’t make any guarantee about future versions of these libraries.

Lightning Container Component Isolation

The HTML Inline Frame Element <iframe> allows you to embed an HTML page in the current HTML page. The embedded HTML page is loaded in a different DOM (with limited access to the parent DOM) and runs in its own context. The Lightning Container Component (lightning:container) is a convenience component that wraps an iframe and provides a simple API to communicate between the iframe container and its content. The Lightning Container Component is in Developer Preview in Spring ’17. The Lightning Container Component can be used to sandbox components or apps built with libraries that don’t run with LockerService. For example, you can use a Lightning Container Component to embed an AngularJS app in a Lightning Component. Here is what it might look like:

The Lightning Container Component is not an optimal solution for fine grained application composition where you would embed multiple iframed AngularJS components on a page: In that case, each component would load the AngularJS framework, communication between components would be limited (postMessage only), and the UI would be constrained by the boundaries of each iframe.

Lightning Container Component Advantages

Native isolation mechanism in the browser

Support for any third-party library, including ones that are not LockerService compliant (libraries are sandboxed in their own DOM/context)

OK for coarse-grained apps

Lightning Container Component Limitations

Limited communication mechanism between components (postMessage)

Components are constrained to a rectangle area on the page. Content may be clipped, rich interactions like drag-and-drop between components may not work, etc.

Heavier/Slower. If there are multiple iframes on a page, each iframe loads its own version of libraries.

Not great for fine-grained app composition

Summary

Before you decide to use a third-party library in a Lightning Component, you should reevaluate if you really need that library. DOM manipulation libraries and UI libraries in particular may no longer be needed when working with the Lightning Component Framework.

LockerService is the preferred isolation mechanism and should be your first choice because it’s more tightly integrated: components run in the same DOM, resulting in a faster and more cohesive user experience. If your library doesn’t support LockerService, you can fall back to iframe-based isolation using the lightning:container component.

LockerService

Lightning Container Component

iframe-based

No

Yes

Components are loaded in the same DOM

Yes

No

Supports all third-party libraries

No. Only compliant libraries will work.

Yes. Libraries are sandboxed in their own DOM/context.

Cohesive UI

Components can grow and shrink. Surrounding DOM elements will reflow.

Components are constrained by iframe boundaries

Inter-component communication

Native LC communication

postMessage

Performance

Faster. All components are loaded in the same DOM.

Slower/Heavier. Each iframed component has to load its dependencies.

Check out the LockerService and the Lightning Container Component documentation to learn more.

Follow @ccoenraets on Twitter.

Show more