Lightning Container in Communities

Starting in Spring ‘19, lightning:container will be supported in Lightning communities as well as in Lightning Experience. In this post, we will cover examples of what you can do with lightning:container in Lightning communities.

If you are familiar with how lightning:container components operate in Salesforce Lightning Experience, there will be a few additional bits of configuration to pay attention to. I also want to show off some of the amazing feats you can accomplish when lightning:container is used in conjunction with other web technologies.

Having a consistent online presence between all aspects of your sites is critical to your company’s brand, but it isn’t always easy to achieve when using multiple tools. In Lightning communities, pieces of your storefront application may be challenging or even impossible to reproduce with existing Lightning components, leaving you with an inconsistent web presence. The lightning:container component is an essential tool to close those gaps and build a seamless online experience for your customers. New Content Security Policy options in Communities also give developers more freedom when developing lightning:container applications.

If you are unfamiliar with lightning:container, I recommend you start with the Lightning Container documentation, and the first Lightning Container developer blog to begin your journey with lightning:container.

A review of Lightning Container

The lightning:container component is a powerful developer-focused component intended to allow you to securely reuse code originally developed for use outside of the Lightning Framework.

Many Salesforce customers have applications or websites built using React, Angular, Vue, or other third-party JavaScript frameworks. You can easily integrate these with Salesforce using lightning:container . I would even encourage you to mix in open source software in your Lightning applications when needed, using this approach.

In some cases, it’s possible to use third-party JavaScript code in a Lightning component. As long as your code is compliant with Locker Service, consider building your application with Lightning components instead. Lightning Container components are meant for coarsely grained applications which do not work within the restrictions of Locker Service. Lightning Container, in essence, uses an iFrame to sandbox the content, making it possible to integrate with Salesforce. It may be tempting to use Lightning Container as a wrapper for all of your third-party components, but it isn’t recommended and it’s likely to cause poor performance. Please review this blog post on the different options and the limits of lightning:container when making your decision.

Watch Lightning Container in action

Let’s take a quick look at a common commerce-focused solution. In this video, you can see a solution that uses React code working seamlessly within a Lightning community. No code understanding needed, just watch it all work without a hitch.

Want to know how it works? The sample application is included in our code samples.

What you’re seeing is just the tip of the iceberg in terms of what is possible. What follows are a series of more technical examples to help you explore other ideas.

Technical examples and sample code

There is a repository of samples, with complete readme, available here. The repository includes both pre-existing examples from this repo and the Lightning Container Component Sample App, plus new samples made specifically for Lightning communities. Some of these samples require you to run a Relaxed-CSP Community and thus will not work correctly in Lightning Experience. Please defer to the README.md files for each sample application, in the /js-apps folder.

Some of these examples require additional specific Content Security Policy (CSP) changes made in the Security tab in Community Builder, or by adding external domains to your CSP Trusted Sites. Please check out this blog post and this help document for more information.

Common themes

In this section, I’ll be highlighting some common recurring themes you’ll run into when working with a lightning:container component, as well as highlighting the appropriate code and referencing the examples in our GitHub repository.

Relative pathing in your application

When building apps for communities, you need to consider that different communities have different path prefixes. So, if you want to put your app on the AppExchange, it must work regardless of path prefix. I suggest telling your JS framework to use relative pathing. Most JS build tools can be configured this way.

In the rare cases where this isn’t possible, you’ll need to dynamically load all of your resources based on the current site and URL. This is a fragile approach and isn’t recommended unless there are no other options.

For example in Angular, go to the angular.json and add:

"projects": {
 "your-project": {
   "root": "./",

When using Angular, you also must build with the –base-path flag:

ng build --base-path "./" --prod

This will create the <base href="./"> tag in the index.html file of your target output directory. All resources should then load correctly in all communities. Follow the configuration in our AngularJS Example.

Another common web development practice is to bootstrap your application using create-react-app. For this use case, all you need to do is add the following to your package.json file.

"homepage": "."

From there, react-scripts build will create the appropriately pathed items. This is used in the react-commerce example.

There are many more examples of relative pathing in the sample GitHub repository. To see them, compare the build configurations of the sample JS applications with their build output, found in the static resources folder. You will see that each JS framework can be configured to use relative pathing, generally with only small modifications to a few configuration files.

MutationObservers

Modern web design generally avoids scroll bars within the page content, especially nested scroll bars. This does not come for free with lightning:container. One strategy to deal with this is to use a MutationObserver to keep track of the size of your content, and then use the post-messaging capabilities of lightning:container to resize the iFrame appropriately. When used correctly, you can create a responsive iFrame that will never have double scrollbars on the desktop, and which works fluidly on mobile devices.

I’ve provided a simple, barebones example of this in action. The green background denotes the content of the lightning:container. See the code in our resizing example.

 

Guest and portal users

Lightning communities fully support lightning:container and it is available to all user types in your communities, including the Guest User Profile. If you are interacting with Salesforce objects via Apex, you’ll need to add access to the appropriate Apex classes to your org’s user profiles. From the profile page, click “Enabled Apex Class Access”, as shown here.

 

For guest users, check out the site Guest User Profile help doc.

WARNING: Guest User access to data is shared with all anonymous users using the Guest User Profile on the site. Make sure any data that you let the Guest User Profile access and create is truly public data and that everyone should have access to that data! Don’t let guest users access sensitive information, and don’t have guest users create records with their personal information.

Browser support

Lightning communities support many browsers, including Internet Explorer 11. Babel, or any other JS compiler, can be used to create production builds of your JavaScript applications that are compatible with Internet Explorer 11 and have the correct polyfills.

Content Security Policy

Salesforce maintains a restrictive Content Security Policy (CSP) when using Lightning communities. The lightning:container iFrame will inherit the same CSP policy as its parent container, so in Lightning Experience it will use the Lightning Experience policy and in a community, it will use the community policy. When using lightning:container, there are a few best practices to follow.

First, we recommend avoiding inline scripts when using lightning:container, especially if you are looking to create a lightning:container for AppExchange. Inline scripting requires the script-src: unsafe-inline directive, which is less secure and is only available in communities not running Strict CSP. Running without Strict CSP may not be an option for all of your potential customers and so that requirement should be avoided if possible. Using inline scripts would also block your lightning:container from working in Lightning Experience.

If you for some reason need to use inline scripts, or you have to load external JS resources, you cannot use Strict CSP in your target community. External JS scripts must also be added to the trusted site whitelist for each community where the lightning:container is intended to run.

A common example of External JS scripts is found in Polymer which, in many applications, downloads the required scripts from Cloudflare.

<script src="https://cdnjs.cloudflare.com/ajax/libs/webcomponentsjs/2.0.2/webcomponents-loader.js"></script>

To load the script, you must add https://cdnjs.cloudflare.com as a trusted script-src in the Security settings of Community Builder.

Another common requirement are external resources such as external data sources and hosted images. External resource domains must all be added as “trusted sites” to your org so they are available. Additions to CSP Trusted Sites can be part of an AppExchange package and should be included in the package with the lightning:container when they are needed.

Conclusion

Through this blog you’ve seen all kinds of technical examples about how to use Lightning Container in Communities. We can’t wait to see what you build next!

Resources

About the author

James Wonsever is a Lead Engineer on Community Cloud for 5 years since the inception of the Napili template. He has been involved with many parts of Community Cloud development.

Leave your comments...

Lightning Container in Communities