Introduction
Many companies face challenges related to scalability and code maintenance. Balancing the maintenance of active clients and the implementation of system updates without delays or interruptions highlights the need for proper software planning and the selection of a suitable architecture for product development.
In this context, the adoption of approaches such as the implementation of Micro Frontends has become common. This strategy allows companies to divide an application into smaller, independent components, providing greater flexibility in maintaining and evolving the system, as well as improving the end-user experience.
What is Micro Frontend (MFE)?
MFEs, or Micro Frontends, are an architectural design approach that divides a frontend application into two or more independent parts. Each part is responsible for a specific functionality and can be developed, tested, and deployed independently. It is similar to adopting a Microservices architecture in a backend application, where an application is divided into small, independent services, each performing a specific function and communicating with each other via APIs.
This approach allows multiple teams to work simultaneously on different parts of an application, increasing efficiency and scalability. The final result is a single application that combines all the parts at runtime.
When consuming Micro Frontends (MFEs), it is generally preferable to use the latest available version, as this ensures access to the latest features, performance improvements, and bug fixes. However, in some cases, it may be necessary to force the use of an older version for stability or compatibility reasons with other systems.
Web Components
First, to understand how MFEs would work in the Salesforce environment, it is important to highlight the concept of Web Components in the frontend universe.
Modern Web Development increasingly uses methods and approaches that prioritize the encapsulation of user interface functionalities, offering an effective way to create interface components that can be reused in different projects and contexts.
With Web Components, the developer's work is simplified to merely showing the browser when and where the component will be used.
Thus, it is very common to see the implementation of Web Components in a
Micro Frontend architecture. However, entering the world of Salesforce
makes everything even easier.
How to implement MFE's in Salesforce Experience Cloud?
Salesforce Experience Cloud is a cloud-based platform that enables companies to create connected, personalized, and scalable experiences for their customers and employees.
Once you break a monolith into more parts, it is necessary to plan to choose the best possible approach for the frontend architecture. For the implementation of MFEs with Salesforce Experience, the most common and used approach is the Shell Application or Shell Architecture
Shell Architecture
In a microfrontends implementation, the Shell Architecture is the main application layer that hosts and manages the microfrontends. Thus, the Shell is responsible for controlling the navigation between different microfrontends, managing their dynamic loading, and facilitating communication between modules through events or messages.
The first step is to identify the different functionalities of the system that can be separated into modules. Each module should have a well-defined interface for communication with other modules. This can include events, APIs, or messaging services.
Salesforce Experience Cloud Shell Application
Development with Lightning Web Components (LWC)
Lightning Web Components is a web component development framework introduced by Salesforce that enables the creation of dynamic and efficient user interfaces on the Salesforce platform. It is based on modern web standards such as HTML, CSS, and JavaScript, and leverages the native functionality of browsers, resulting in better performance and lower resource consumption.
Each component should be developed with its own logic and user interface. For communication and integration between them, you can use Salesforce's messaging service, Lightning Message Service. This service allows LWC components to communicate efficiently, regardless of whether they are in the same component tree or not. It is particularly useful in complex architectures like Micro Frontends, where communication between independent modules is essential.
Lightning Message Service (LMS)
- Publish and Subscribe to Messages: Allows one component to publish a message and another component (or components) to subscribe to that message to receive data or notifications.
- Message Context: Provides the necessary context to send or receive messages.
- Custom Message Channels: Define the types of messages that will be exchanged between components.
To illustrate, here is a small example of implementation using LWC, Lightning Message Service and Salesforce Experience Cloud.
The first step is to identify the different functionalities of the system that can be separated into modules. For example, in a CRM, you can have modules for lead management, contact management, and reporting.
Message Channel
First, we create the Lead Channel, which is a messaging channel of the Lightning Message Service that you define in your Salesforce project using an XML file.
<?xml version="1.0" encoding="UTF-8"?>
<MessageChannel xmlns="http://soap.sforce.com/2006/04/metadata">
<description>Lead Channel Message</description>
<isExposed>true</isExposed>
<masterLabel>Lead Channel</masterLabel>
</MessageChannel>
Lead Module
After that, we create the leadModule component, which publishes messages about new leads using the Lightning Message Service (LMS).
<template>
<lightning-card title="Lead Module">
<div class="slds-m-around_medium">
<lightning-button label="Create Lead" onclick={handleCreateLead}></lightning-button>
</div>
</lightning-card>
</template>
import { LightningElement, wire } from 'lwc';
import { publish, MessageContext } from 'lightning/messageService';
import LEAD_CHANNEL from '@salesforce/messageChannel/LeadChannel__c';
export default class LeadModule extends LightningElement {
@wire(MessageContext)
messageContext;
handleCreateLead() {
const lead = { name: 'John Doe', company: 'Company Name' };
publish(this.messageContext, LEAD_CHANNEL, lead);
}
}
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>59.0</apiVersion>
<isExposed>true</isExposed>
<targets>
<target>lightning__AppPage</target>
<target>lightning__RecordPage</target>
<target>lightning__HomePage</target>
<target>lightningCommunity__Default</target>
<target>lightningCommunity__Page</target>
</targets>
</LightningComponentBundle>
Then, we develop the contactModule component, which subscribes to the LeadChannel message channel and displays information about the received leads.
Contact Module
<template>
<lightning-card title="Contact Module">
<div class="slds-m-around_medium">
<template if:true={leadCreated}>
<p>Lead created: {leadName}, {leadCompany}</p>
</template>
<template if:false={leadCreated}>
<p>There are no leads created.</p>
</template>
</div>
</lightning-card>
</template>
import { LightningElement, track, wire } from 'lwc';
import { subscribe, MessageContext } from 'lightning/messageService';
import LEAD_CHANNEL from '@salesforce/messageChannel/LeadChannel__c';
export default class ContactModule extends LightningElement {
subscription = null;
@track leadCreated = false;
@track leadName = '';
@track leadCompany = '';
@wire(MessageContext)
messageContext;
connectedCallback() {
this.subscription = subscribe(this.messageContext, LEAD_CHANNEL, (message) => this.handleLeadCreated(message));
}
handleLeadCreated(message) {
this.leadCreated = true;
this.leadName = message.name;
this.leadCompany = message.company;
}
}
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>59.0</apiVersion>
<isExposed>true</isExposed>
<targets>
<target>lightning__AppPage</target>
<target>lightning__RecordPage</target>
<target>lightning__HomePage</target>
<target>lightningCommunity__Default</target>
<target>lightningCommunity__Page</target>
</targets>
</LightningComponentBundle>
To integrate these components, we create the appContainer, which organizes leadModule and contactModule into a single interface.
App Container
<template>
<lightning-layout multiple-rows="true">
<lightning-layout-item size="12" padding="around-small">
<c-lead-module></c-lead-module>
</lightning-layout-item>
<lightning-layout-item size="12" padding="around-small">
<c-contact-module></c-contact-module>
</lightning-layout-item>
</lightning-layout>
</template>
This MFE architecture allows each component to be developed and maintained independently, promoting scalability and flexibility.
Conclusion
The Micro Frontends (MFEs) architecture is evidenced in this implementation through the decomposition of the application into independent components that communicate with each other using the Lightning Message Service.
This implementation not only demonstrates the ability to create and integrate LWC components but also highlights the benefits of the Micro Frontends architecture in the context of Salesforce. The achieved modularity allows for better maintenance and evolution of the system, making it more adaptable to changes and future organizational needs.
Top comments (0)