Discover Summer ’20 Release features! We are sharing five release highlights for Developers and Admins, curated and published by our evangelists as part of Learn MOAR. Complete the trailmix by July 31, 2020 to get a special community badge, and unlock a $10 contribution to Libraries Without Borders (Bibliothèques Sans Frontières).
In Winter ’20, we announced the Lightning Message Service (LMS) cross DOM messaging API. In Summer ‘20 it is now generally available. This makes building seamless user experiences easier than ever, regardless of whether you’ve implemented new Lightning Web Components (LWC), or have a UI that uses a combination of LWC, existing Aura components, or even Visualforce pages. To incorporate LMS into our sample apps, I had the opportunity to get access to LMS during the developer preview and beta cycles
Building for the modern Salesforce UI
Given the evolution of the modern Salesforce UI, developers frequently deal with a blend of UI technologies. Many customers have implemented a lot of features in Visualforce and Aura that work, and reimplementing them for the sake of new technology is not practical. Some orgs have now added web components features since the launch of Lighting Web Components a year and a half ago.
But since the launch of LWC, there have been two main obstacles developers face when building a seamless user experience using modular components. The first has existed since the launch of the Lightning Experience: no supported platform feature to enable easy cross DOM events between Visualforce pages and Lightning components. The second was new: no supported platform feature to enable cross DOM events between LWCs. And while we did create the OSS
c-pubsub shim component, we always stated this was a temporary solution.
LMS has smashed both of those barriers with an easy to use API implemented in LWC, Aura, and Visualforce. This allows publishing and subscribing to and from any of these technologies in the same Salesforce UI. It even allows pub/sub between the utility bar, utility bar popups, and the rest of your application’s UI.
Awesome! How does it work?
Underneath the covers, LMS is a publish/subscribe service layer that is independent of the DOM. In the browser, the built-in
CustomEvent API is designed so that a
dispatchEvent call bubbles up the DOM tree. But there’s no native API to publish events between two separate DOM branches. LMS solves that.
But Visualforce poses a trickier problem: crossing the iFrame boundary. Visualforce has always used the iFrame sandbox feature as a security mechanism to ensure that the composed Visualforce UI would not compromise customer security, were the Visualforce page itself be compromised. Getting a message across this boundary is done using the
window.postMessage() API, but this is not trivial to implement.
Image by Pixabay.com
So the second thing you can expect from LMS is for the Visualforce implementation to abstract away the complexity of using the
postMessage() API when your page is included on a Lightning page (FlexiPage) in App Builder. Whether your Visualforce page needs to send a message, or subscribe to a message, wiring it into the Lightning Experience has never been easier.
Note that traversing the Visualforce iFrame boundary only works if a developer explicitly enables it in the metadata for the message channel. I’ll show you how to do this a bit later.
What’s new in Summer ’20
The primary change that will come with LMS being GA is the addition of message scopes. I spent some time with the engineering team to understand scopes better.
Simply put, scopes define the implicit context that decides which subscribers will receive messages. There are two scopes: active (default) and application.
The active scope automatically enables and disables which subscribers will receive a message based on active parts of the user interface. An active part of the UI could be a standard application tab or a Lightning console tab that is currently in the selected state. An inactive part of the UI would be one of those tabs that is visible, but not currently in the selected state. As tabs that contain components that implement LMS become active or inactive, there is a context that tracks which LMS-implementing components are currently available to receive messages.
The application scope is a global scope, allowing subscribers in inactive parts of the UI to still receive messages.
Generally, developers should implement LMS in the active scope. The primary use case for application scope is Lightning Console.
Going into the detail of using LMS scopes is beyond the reach of this blog post. In the examples below, we use the default active scope.
I’m sold. Show me how to use it.
Using LMS requires a few elements.
- A message channel defined in metadata
- A LWC, Aura component, or Visualforce publishing a message
- A LWC, Aura component, or Visualforce subscribing to a message
For the examples, I’m using the implementation of LMS we’ve been adding to the LWC Recipes app. This is currently working in the prerelease/summer20 branch, but we will merge it into master once Summer ‘20 goes live. The use case is for the user to select a record from a list. This publishes a message with the record id value. Subscribers then use that record id to display the selected record. In the Winter ’20 pilot announcement blog post, there was a comprehensive look at all three technologies as both subscriber and publisher. So for the sake of brevity, I’ll show the LWC publisher, and an Aura and Visualforce subscriber. But rest assured, in the examples, you can see subscribers and publishers in all three technologies.
Let’s start with the message channel.
Create a message channel
Message channels are a pretty simple piece of metadata. As is typical with metadata, the file name is used to derive the developer name for the message channel. To reference it in code, combine the filename with a
__c suffix. For example, the
Record_Selected message channel shown below would be referenced as
Some may wonder why message channels exist, when they are an entirely client-side feature. One reason is to have an artifact that you can check into version control. Another is so Salesforce can perform reference checks against any message channels used in a LWC, Aura component, or Visualforce page. If you attempt to save code that uses a message channel that doesn’t exist in metadata, you’ll be blocked and notified. Lastly, when you use a message channel (for instance when importing into a web component in VS Code) the language server tooling will kick in and help you out with intellisense.
The definition of the message channel metadata includes only one required XML element, the
<masterLabel> which defines a user-friendly label. To reiterate, the channel name as referenced in code is derived from the metadata file name with an appended
Any message channel that communicates across the Visualforce iFrame boundary must also set the
<isExposed> tag value to
When you need to use a message channel, each technology (LWC, Aura, Visualforce) has its own idiomatic way to get a handle to it.
A couple of final notes on the metadata. First off, you manually create this metadata XML for the moment (see the instructions on where to put it and how to get it into your org in the developer guide). But given how simple the metadata structure is, that should not be much of an obstacle. The other has to do with the
__c suffix borrowed from custom Salesforce objects. That threw me at first, but the use of a message channel is so sharply distinct from that of a Salesforce object, this first impression quickly melted into the background for me.
Let’s look at a few examples of how we implement LMS with the above message channel and the LMS engine itself.
Implementing a LWC publisher
- The required members of the LMS engine through the
lightning/messageServicemodule. In the case of a publisher, these are
MessageContextobject. If you are subscribing, you’ll need to import
unsubscribe, and a few others.
@salesforce/messageChannel/Record_Selected__c. This import is the same regardless of whether the component is a subscriber or publisher.
Here’s the example publisher web component from the LWC Recipes example. Note that in this case we’re calling
publish in an event handler that is fired when a record is selected from a list.
messageContext object above was created with the
@wire adaptor. This object serves two purposes. The first is to implicitly unhook all LMS features when the component is destroyed. The other is to make sure messages are sent only to active scoped LMS implementations.
Implementing an Aura subscriber
As you’d expect in Aura, the implementation of LMS is partly encapsulated in the component markup (
- Get a handle to the message service engine
- Set the context of the service
- Subscribe to a message channel
- Identify the handler for that subscription
Aura encapsulates all of this in a single bit of markup, as you can see in the
It’s important to note that LMS, as surfaced to Aura, auto-subscribes any component implementing
lightning:messageChannel. There’s no other LMS-specific code to implement in order to subscribe. The handler will receive the payload and any data passed from the publisher. Your component can then respond as necessary (refresh data, update component state, etc.). There is more on this Aura component in the Lightning component reference.
Please note that publishers in Aura use the same
<lightning:messageChannel> tag, but
Implementing a Visualforce subscriber
Visualforce implements LMS in two different parts of the Visualforce framework.
The LMS engine is surfaced to Visualforce on the client side through the
sforce.one object. You can find the
unsubscribe LMS functions there.
The message context is handled implicitly for LMS in Visualforce.
The LMS message channel that you plan to use is surfaced through the server-side
$MessageChannel global variable. For instance, the
Record_Selected__c message channel shown above is accessed through
And here you can see the call to subscribe to the message channel in the static resource.
One thing to look out for in the Visualforce subscriber example is that we’ve implemented two pages. The examples include both a page that uses traditional postback actions, and another page using the Visualforce remote object API. These show that there’s no need to reimplement your existing Visualforce page’s server connection just to wire it up to the LWC and Aura components you’ve built in Lightning.
Important LMS considerations
We’ve already mentioned some caveats but there are a few more to consider.
LMS is not currently supported in Lightning communities, or in Lightning Out. And LMS for Visualforce is not supported in the Salesforce Mobile app.
For the conclusive list of implementation considerations, be sure to check the Lightning web component, Aura, and Visualforce developer guides, as each technology as some unique constraints to be aware of.
LMS for interactive cross technology UI development
LMS represents a watershed moment in building the Lightning UI. The number of places where you can incorporate existing investments in custom UI has just increased drastically.
So go clone the latest version of the LWC Recipes app (currently on the prerelease/summer20 branch). Take a look at the code, and see what you can build today with LMS. If you’ve implemented a something using the unsupported
c-pubsub component, now is the time to get it working with this supported platform feature.
I’d like to add a special acknowledgement to Trenton Johnson, and the whole Visualforce engineering team who were invaluable in the project to implement a set of recipes for LMS, and the writing of this blog post.
- Clone LWC Recipes and start using it
- Check out the docs for LWC
- Check out the docs for Aura
- Check out the docs for Visualforce
About the author