Understanding Lightning Message Service (LMS) & MessageChannel in LWC

Introduction

When working with Salesforce Lightning Web Components (LWC), communication between components is crucial. Enter the Lightning Message Service (LMS). In this blog post, we'll delve deep into how LMS and MessageChannel empower developers to build more integrated, flexible, and efficient applications on the Salesforce platform.

What is Lightning Message Service (LMS)?

Lightning Message Service is Salesforce’s solution for enabling communication between Lightning components — whether they are Aura, Visualforce, or LWC. In essence, LMS is a mediator, allowing components across the Salesforce ecosystem to exchange information seamlessly.

Why Use LMS in LWC?

  1. Unified Communication: Unlike other communication methods that are restricted to a single UI framework, LMS bridges the gap, ensuring all your components can "speak" to each other regardless of their origin.
  2. Loose Coupling: Components do not need to be directly aware of each other, making your applications more modular and maintainable.
  3. Event-Driven Architecture: LMS capitalizes on an event-driven approach, making it highly scalable and efficient for complex applications.

MessageChannel: The Heartbeat of LMS

While LMS acts as the messenger, MessageChannel is the established protocol or "language" it uses. Here's how it works:

  1. Definition: MessageChannel provides a predefined contract that components can subscribe to or publish. Think of it as a radio frequency — components can tune in (subscribe) or broadcast (publish) messages.
  2. Flexibility: Multiple components can listen to a single MessageChannel, making it immensely powerful for broad communications.
  3. Best Practice: Always keep your MessageChannel definitions fine-tuned to avoid unnecessary broadcasts. This ensures optimal performance and clarity in communication.

Implementing LMS in LWC

Here's a basic step-by-step guide:

  1. Create a Lightning Message Channel:

This has to be created using Visual Studio Code and we cannot create it from the Salesforce Org. We need to specify the MessageChannelName as well as LightningMessageFields using which we want to transfer the data.

<?xml version="1.0" encoding="UTF-8"?>
<lightningMessageChannel xmlns="http://soap.force.com/2006/04/metadata">
    <masterLabel>Account Message Channel</masterLabel>
    <isExposed>true</isExposed>
    <description>This is used to send data from LWC component using messaging channel</description>

    <lightningMessageFields>
        <description>This is the tax percentage of the record</description>
        <fieldName>taxPercent</fieldName>
    </lightningMessageFields>
    <lightningMessageFields>
        <description>This is the name of the record</description>
        <fieldName>greeting</fieldName>
    </lightningMessageFields>

</lightningMessageChannel>

AccountMessageChannel.messageChannel-meta.xml

2. Create a publisher:

Let me implement a publisher that publishes the data using Lightning Message Channel.

<template>
  <lightning-button
    label="Publisher"
    onclick={handlePublish}
  ></lightning-button>
</template>

publisher.html

3. Publish the data:

Then, am gonna take the help of the JS controller and publish the data using a named import called Publish() .

import { LightningElement, wire } from "lwc";

// 1. Import all the dependencies
import { MessageContext, publish } from "lightning/messageService";
import ACCOUNT_MESSAGE_CHANNEL from "@salesforce/messageChannel/AccountMessageChannel__c";

export default class Publisher extends LightningElement {
  // 2. Wire the message context
  @wire(MessageContext)
  messageContext;

  handlePublish() {
    //3. Create the payload
    const payload = {
      taxPercent: 10.8,
      greeting: "HEY!!"
    };
	
    // 4. publish the data to message channel
    publish(this.messageContext, ACCOUNT_MESSAGE_CHANNEL, payload);
  }
}

publisher.js

You can specify where you want to expose the component using the below metadata file.

<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>52.0</apiVersion>
    <isExposed>true</isExposed>
    <targets>
        <target>lightning__AppPage</target>
        <target>lightning__RecordPage</target>
        <target>lightning__HomePage</target>
    </targets>
</LightningComponentBundle>

publisher.js-meta.xml

4. Create an interface to Subscribe:

Then am gonna create a subscriber, that will subscribe to the Message Channel.

<template>
  <div>
    <span>
      <p>HEY!! Salesforce Casts</p>
    </span>
  </div>
  <lightning-button label="Subscribe" oonclick={handleSubscribe}></lightning_button>
  
  <lightning-button label="Unsubscribe" oonclick={handleUnsubscribe}></lightning_button>
  <p class="slds-no-print"></p>
  {greeting}
</template>

subscriber.html

5. Create a Subscriber Listener:

Finally, let's use the JS controller in the subscriber web component to subscribe to the MessageChannel.

import { LightningElement, wire } from "lwc";

// 1. Import the dependencies
import {
  MessageContext,
  subscribe,
  unsubscribe
} from "lightning/messageService";

import ACCOUNT_MESSAGE_CHANNEL from "@salesforce/messageChannel/AccountMessageChannel__c";

export default class Subscriber extends LightningElement {
  // 2. Wire the message context to a prop
  @wire(MessageContext)
  messageContext;

  taxPercent;
  greeting;
  subscriptionStatus = null;

  // 3. Subscribe to the Message Channel on click of the button
  handleSubscribe() {
    if (!this.subscriptionStatus) {
      this.subscriptionStatus = subscribe(
        this.messageContext,
        ACCOUNT_MESSAGE_CHANNEL,
        (message) => {
          // This is the event listener that gets invoked when 
          // data is published to the MessageChannel
          this.handleListener(message);
        }
      );
    }
  }
  
  handleUnsubscribe() {
    unsubscribe(this.subscriptionStatus);
    this.subscriptionStatus = null;
  }
  
  handleListener(message) {
    console.log(JSON.stringify(message));
    this.greeting = message.greeting;
    this.taxPercent = message.taxPercent;
  }
}

subscriber.js

Here is the metadata file of the subscriber.

<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>52.0</apiVersion>
    <isExposed>true</isExposed>
    <targets>
        <target>lightning__AppPage</target>
        <target>lightning__RecordPage</target>
        <target>lightning__HomePage</target>
        <target>lightning__UtilityBar</target>
    </targets>
</LightningComponentBundle>

subscriber.js-meta.xml

Conclusion

Lightning Message Service (LMS) with MessageChannel is an indispensable tool for every Salesforce developer. By facilitating component communication across different Salesforce UI technologies, LMS ensures that your applications are not only robust but also future-proof.

If you found this article insightful, don't forget to share it with your peers. For more insights into Salesforce development, stay tuned!

Also, check