Enhanced Performance with Lightning Web Components

Enhanced Performance with Lightning Web Components

Sharing is caring!

Salesforce has recently come up with Lightning web components, as part of Spring 19, prerelease. It is a new programming model based on modern web standards which allows the developer to build Lightning components. The webstack has evolved in the past 5 years, starting from 2014. Let us try to understand the importance of Lightning web components.

First, we understand the challenges faced by the traditional web stack.

Challenges Faced by Traditional Web Stack

The challenges faced by the Lightning web contents are:

  • Web was not providing the features required by the framework and this resulted in lack of innovations.
  • It lacked the full stack required by the developers to build large scale web applications.
  • Language extensions, templates and component models all provided by the framework and not the platform provided.
  • Proliferation of frameworks only led us into fragmentation.
    Apps and Components are not interoperable.
  • Difficulty in transferring skills and ramping up of developers.
  • No continuous UI transformations.
  • Lesser standard UI elements and no support for custom UI elements.

Now, we come to “Why Lightning Web Component?”.

Why Lightning Web Component?

Lightning web component is the Salesforce implementation of the new breed of lightweight frameworks based on new web stack, 2019. This ensures exceptional level of performance for the LWCs.

This is what Salesforce thinks about Lightning Web Components: 


“With Lightning Web Components, we are giving developers a standards-driven JavaScript model for building enterprise apps on Lightning. Every time we release a new platform capability we see an acceleration of innovation in our 150,000 customer base, and we are excited to see what our community of developers will do with Lightning Web Components.”

 Mike Rosenbaum, EVP of Product, Salesforce

LWC uses some of the features available in the ECMAScript7 and beyond such as:

  • Custom elements and templates
  • Shadow DOM
  • Other language constructs
  • Decorators and modules
lighting components

Lightning web component offer a layer of specialized services on top of the core stack and these are:

  • Base Lightning Components
  • Lightning Data Services
  • User Interface APIs

Base Lightning Components
This a set of over 70 UI components to build custom elements.
Lightning Data Services
This provides the declarative access to Salesforce data and metadata, data synchronization and data caching.
User Interface APIs
This is for enhanced productivity gains for metadata awareness of Base Lightning components and Lightning Data Services.

Let us delve with cutting edge advantages of Lightning Web Components:

Cutting edge advantages of Lightning Web Components

Some of the advantages for Lightning Web Components(LWC) are:

  • Interoperability
  • Performance
  • Referential Integrity
  • Ease of Use

Interoperability of Lightning Web Components

It is possible to embed the Lightning Web Components inside the Aura Components but Aura components may not put inside LIghtning component. They help to access the same underlying services and communicate with events. Lightning web components and Aura Components can be used to build apps. Components used in building these apps can interoperate and work side by side, in the same app.

Performance

The Lightning Web Components significantly outperforms the Aura Components, which were earlier known as Lightning components for better user experience. Since the Aura components were built on Aura framework, a layer of abstraction was added or more code. On the contrary, LWCs are based on native web standards, built-in to the browsers and hence no extra code is needed to execute and it requires no complex abstractions to run on the browser.

Referential Integrity

Referential Integrity in Lightning Web Components is ensured by importing of static schema elements. This ensures the LWCs are made metadata aware. This means that no one will be able to delete any of the objects or fields, present in the Javascript code.

Ease of Use

It is possible to deploy LWCs, after development with just clicks – not by code to the application developed.

Let us now throw some more insights on interoperability of Aura and Lightning web components.

Interoperability with LWCs and Aura Components
The Lightning Web Components address the major concern of the developers for application currently in the development stage. LWCs seem to be closer to Javascript.

Both Aura and LWC components can exist on the same page and can communicate with each other, through events but with some restrictions. The more Aura components are converted into LWCs, the more is the increase in the performance.

Please refer to our next blogs with LWCs on How to Create Lightning Web Components?

You can gather more knowledge on LWCs with the following links:

Introducing Lightning Web Components
https://developer.salesforce.com/blogs/2018/12/introducing-lightning-web-components.html

Introducing Lightning Web Components Recipes, Patterns and Best Practices
https://developer.salesforce.com/blogs/2018/12/introducing-lightning-web-components-recipes-patterns-and-best-practices.html

 

Example Lightning web component

Scenario :
I have a requirement where I was creating sObject record multiple times with all the fields, for that I created custom record page web component.

Description about component :
Component uses a child component for lookUp type fields named as LookUp .

“LookUp” Lightning Web Component

<template>
<div class="">
<template if:true={isIdReturned}>
<div class="slds-form-element">
<label class="slds-form-element__label" for="text-input-id-1">{fieldlabel}</label>
<div class="slds-form-element__control slds-input-has-icon slds-input-has-icon_right customBox">
<input type="text" id="text-input-id-1" class="slds-input" value={recordName} ></input>
<lightning-button-icon variant="bare" icon-name="utility:close" alternative-text="Delete" onclick={clearSelected}
class="slds-icon slds-input__icon slds-input__icon_right slds-icon-text-default"></lightning-button-icon>
</div>
</div>
</template>
<template if:true={isListOpen}>
<lightning-input type="search" onkeyup={handleKeyChange} class="" label={fieldlabel} name={fieldname} value={searchKey}></lightning-input>
<template if:true={getRecords.data}>
<div class="fixSize">
<div id="listbox-unique-id" role="listbox" class="" style="max-height:200px;position: relative;">
<ul class="slds-scrollable slds-listbox slds-listbox_vertical slds-dropdown slds-dropdown_fluid" role="presentation" style="max-height:200px;">
<template for:each={getRecords.data} for:item="Obj">
<li role="presentation" class="slds-listbox__item" key={Obj.Id} title={Obj.Name} id={Obj.Id} onclick={handleRecordClick}>
<div id={Obj.Id} class="slds-media slds-listbox__option slds-listbox__option_entity slds-listbox__option_has-meta" role="option">
<span class="slds-media__figure">
<span class="slds-icon_container slds-icon-standard-account" title="Description of icon when needed">
<lightning-icon size="small" icon-name="custom:custom11" class="slds-icon slds-icon_small"></lightning-icon>
<span class="slds-assistive-text">Description of icon when needed</span>
</span>
</span>
<span class="slds-media__body">
<span class="slds-listbox__option-text slds-listbox__option-text_entity">{Obj.Name}</span>
</span>
</div>
</li>
</template>
</ul>
</div>
</div>
</template>
</template>
</div>
</template>

/* eslint-disable no-console */
import { LightningElement, track, wire ,api } from 'lwc';
import getLookupRecord from '@salesforce/apex/CustomLookupContoller.getLookupRecord_Apex';

export default class Lookup extends LightningElement {
@track searchKey = '';
@api selectedid ;
@api objname ;
@api fieldname ;
@api fieldlabel ;
@track recordType = '';
@track isListOpen = true;
@track lookupValue = false;
@track recordName = '';

@wire(getLookupRecord, { valueEnter: '$searchKey' , objName: '$objname',recordType: '' })
getRecords;

handleKeyChange(event) {
var searchvalue = event.target.value;
this.searchKey = searchvalue;
}
handleRecordClick(event) {
console.info('event.target.id :: '+event.currentTarget.id);
console.info('event.currentTarget.title :: '+event.currentTarget.title);
let CurrentId = event.currentTarget.id.split('-');
this.recordName = event.currentTarget.title;
console.info('id :: '+ CurrentId[0]);
this.selectedid = CurrentId[0];
this.isListOpen = false;
this.isIdReturned = true;
const returnId = new CustomEvent('selected',{
detail : {recordId :CurrentId[0],
fieldname : this.fieldname},
});
//Fire Evnet
this.dispatchEvent(returnId);
}
clearSelected() {
console.log('working..');
this.isListOpen =true;
this.isIdReturned = false;
}
}

<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata" fqn="lookup">
<apiVersion>45.0</apiVersion>
<isExposed>false</isExposed>
</LightningComponentBundle>

/*LookUp.css*/
.slds-combobox__input,
.slds-combobox_container {
transition: border .1s linear, box-shadow .1 linear;
}

.slds-combobox__input {
box-shadow: none;
}

.slds-combobox__input.has-custom-border {
box-shadow: 0 0 0 2px #fff inset, 0 0 0 3px rgb(221, 219, 218) inset;
}

.slds-combobox__input.has-custom-error {
border: 1px solid rgb(194, 57, 52);
box-shadow: rgb(194, 57, 52) 0 0 0 1px inset;
}

.slds-combobox_container.has-custom-error {
border: none !important;
}

.slds-combobox__input.has-custom-height {
height: 32px !important;
}

.form-error {
color: rgb(194, 57, 52);
display: block;
}
.fixSize {
height: 100px;
overflow-y: scroll;
}
.customBox {
border: 1px solid rgb(217, 219, 221);
border-radius: .25rem;
padding: 2px;
}

Below is the Lightning Web Component for recordPage

<template>
<div>
<template if:true={ready}>
<section role="dialog" tabindex="-1" aria-labelledby="modal-heading-01" aria-modal="true" aria-describedby="modal-content-id-1" class="slds-modal slds-fade-in-open">
<div class="slds-modal__container">
<!-- ###### MODAL BOX HEADER Start ######-->
<header class="slds-modal__header">
<h2 id="modal-heading-01" class="slds-text-heading_medium slds-hyphenate">Create {ObjectName}</h2>
</header>
<!--###### MODAL BOX BODY Part Start######-->
<div class="slds-modal__content slds-p-around_medium" id="modal-content-id-1">
<lightning-layout multiple-rows="true" class="">
<template for:each={returnList} for:item="obj">
<lightning-layout-item key={obj.fieldName} size="6" padding="around-small" multiple-rows="true">
<template if:true={obj.isMultipickList}>
<lightning-dual-listbox name={obj.fieldName}
label={obj.fieldLabel}
source-label="Available"
selected-label="Selected"
field-level-help="This is a dual listbox"
options={obj.PickFieldList}
value={obj.MultiPickListAnswer}></lightning-dual-listbox>
<lightning-input type="date" name="input1" label="Enter a date" ></lightning-input>
</template>
<template if:true={obj.isPickList}>
<lightning-combobox
name={obj.fieldName}
label={obj.fieldLabel}
value={selectedValue}
placeholder="--Select--"
options={obj.PickFieldList}
onchange={handlePickListChange} ></lightning-combobox>
</template>
<template if:true={obj.isRefrence}>
<c-lookup selectedid={obj.SelectedValue} objname={obj.ObjectName} fieldname={obj.fieldName} fieldlabel={obj.fieldLabel} onselected={getReturnId}></c-lookup>
</template>
<template if:true={obj.isNormal}>
<lightning-input type={obj.fieldType} name={obj.fieldName} label={obj.fieldLabel} value={obj.SelectedValue} ></lightning-input>
</template>
</lightning-layout-item>
</template>
</lightning-layout>
</div>
<!--###### MODAL BOX FOOTER Part Start ######-->
<footer class="slds-modal__footer">
<lightning-button variant="brand" label="Save" title="Save" icon-name="utility:save" class="slds-m-left_x-small slds-m-top_medium" onclick={handleSaveClick}></lightning-button>
<lightning-button variant="brand" label="Reset" title="Reset" icon-name="utility:refresh" class="slds-m-left_x-small slds-m-top-medium" onclick={handleResetClick}></lightning-button>
</footer>
</div>
</section>
<div class="slds-backdrop slds-backdrop_open"></div>
</template>
</div>
</template>

/*RecordPage.js*/
/* eslint-disable no-console */
import { LightningElement, track, wire } from 'lwc';
import getAllFields from '@salesforce/apex/recordPageController.getAllFields';
import saveData from '@salesforce/apex/recordPageController.saveData';
export default class RecordPage extends LightningElement {
@track ObjectName = 'Account' ;
@track selectedValue = '' ;
@track returnList = [] ;
@track saveDataList = [] ;
@track resetDataList = [] ;
@track currentObject = {} ;
@track ready = true;
@wire(getAllFields,{objectName: '$ObjectName'})
wiredData({data,error}){
if(data){
this.returnList = data ;
this.resetDataList = data;
// console.log('data->>'+JSON.stringify(data));
// console.log('this.returnList->>'+JSON.stringify(this.returnList));
}else if(error){
console.log('error->>'+JSON.stringify(error));
}
}

//Below in Init for LWC.
connectedCallback() {}
/* method for saving record*/
handleSaveClick(event){
//console.info('returnList :: '+JSON.stringify(this.returnList));
this.template.querySelectorAll('lightning-input').forEach(each => {
this.currentObject[each.name] = each.value ;
//this.currentObject.sObjectType= this.ObjectName ;
});
console.info('ObjectData :: '+JSON.stringify(this.currentObject));
let tempObj = this.currentObject;
tempObj.sObjectType = this.ObjectName;
console.info('ObjectData :: '+JSON.stringify(tempObj));
/* console.info('selectedValue :: '+this.selectedValue); */
saveData({
recordData: tempObj
})
.then(result => {
console.log('result>>'+JSON.stringify(result));
})
.catch((error) => {
console.log('Error received: code' + JSON.stringify(error));
});
}
/* method for saving record*/
handleResetClick(event){
this.returnList = this.resetDataList ;
this.currentObject = {} ;
this.ready = false ;
this.ready = true ;
}
handlePickListChange(event){
try{
this.currentObject[event.target.name] = event.target.value;
console.info('this.currentObject :: '+JSON.stringify(this.currentObject));
}catch(ex){
console.info('ERROR:: '+ex);
}

}
getReturnId(event){
try{
let EventReturn = event.detail;
this.currentObject[EventReturn.fieldname] = EventReturn.recordId ;
console.info('EventReturn:: '+JSON.stringify(EventReturn));
}catch(ex){
console.info('ERROR:: '+ex);
}

}
}

/*RecordPage.js-meta.xml*/
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata" fqn="recordPage">
<apiVersion>45.0</apiVersion>
<isExposed>false</isExposed>
</LightningComponentBundle>

Conclusion

We conclude to say that as the web stack has evolved in the past 5 years, from 2014 to 2019. LWCs is a new programming model based on modern web standards which allows the developers to build Lightning components. Lightning web component offers a layer of specialized services on top of the core stack.

One the best cutting edge advantage of LWCs is that of interoperability with the Aura components. Both the components can exist on the same page and can communicate with each other, through events – but with some restrictions. As Aura components are converted more into LWCs, there is a chance of increased performance.

Akshay Dhiman

Chief Technical Officer
" Extensive experience in System Architecture, Project Management, and Delivery "

Leave a Reply

Close Menu