Lwc-All The Very Best
Lwc-All The Very Best
To increase performance
2019
Introduction
Bohdan Dovhan - Senior Salesforce Developer and Salesforce Development Team Lead
Salesforce Certified Development Lifecycle & Deployment Designer
Salesforce Certified Platform Developer I
Salesforce Certified Platform Developer II
Salesforce Certified Platform App Builder
8 years of Development experience
5 years of Development on Salesforce platform
SF UI Dev Tools
Salesforce: point-and-click tools and development tools
UI Development frameworks:
Visualforce
Lightning Aura Components
Lightning Web Components (Brand new since Spring’19 release)
UI Development Tools:
Developer Console, many IDEs (VF, Aura)
VS Code (LWC, Aura, VF)
Does your IDE support LWC development? If it does not, migrate to VS Code
LWC
Lightning web components (LWC) are a new programming model for the Lightning
Component Framework that is released in the Spring `19 release and is
available since December of 2018. This programming model is architected with
three principles in mind.
Align with modern web standards
Interoperability with the original Aura-based Lightning development
model
Better Performance
LWC are compliant with most ES2015 (also known as ES6) and later standards
that have seen good adoption across modern browsers.
LWC are more secure, since they add CSS isolation, script isolation, DOM
isolation, and a more limited event scope.
LWC have better performance because of leveraging native DOM support.
LWC can be unit tested with Jest framework but such tests are not stored in
Salesforce, these tests cannot be run on cloud. Node.js, npm and Jest should
be installed on Developer machine to be able to run them.
Aura vs LWC
LWC Migration Plan
Aura Components can contain LWC. LWC cannot contain Aura
Components.
1. To develop brand new UI: try to use LWC
2. To increase performance: refactor slowest children to LWC or everything
3. If feature is not supported by LWC: use Aura completely or wrap LWC with Aura
At the current Spring 19 release Lightning Web Components are not supported in
Lightning Actions,
Utility Bar,
Console,
Flows,
Visualforce pages and
external systems
Prerequisites
LWC cannot be developed in Developer Console.
VS Code with Salesforce Extensions pack is recommended (however any other editor can be used).
To reuse code in Aura Component C of Aura Components A and B, A should inherit B or vice versa and
then C can inherit A or B to reuse both code of A and B
To reuse code in Lightning Web Component C of LWC A and B, C can import two modules A and B.
A doesn’t require to import B and B doesn’t require to have A imported.
Create SFDX Project
To work with Lightning Web Component, SFDX project should be created first to be able to deploy and
retrieve source by using corresponding force:source:deploy and force:source:retrieve
commands.
To create SFDX project in Visual Studio Code, we need to invoke hot key combination Ctrl-Shift-P in
Windows (or Cmd-Shift-P in Macs) and then either select or type SFDX: Create Project and select a
name for it, like “demo”. Watch this video GIF image to see this in action.
Also SFDX Project can be created by command line directly
Create Lightning
To create Lightning Aura Component, menu item SFDX: Create Lightning Component can be used and
name for a component should be chosen, like AuraCmp
To display output panel and monitor which SFDX command is executed under hood, a key combination
Ctrl-Shift-U can be used on Windows (or Cmd-Shift-U on Macs) or corresponding menu item can
be used. In Output panel dropdown Salesforce CLI should be selected to be able to see SFDX
commands run in the background.
Create Aura Comp
As we can see, command
sfdx force:lightning:component:create --componentname AuraCmp --outputdir force-
app\main\default\aura
is run under the hood.
We can run in terminal to create another Aura component with name AuraCmpHello.
To switch to Terminal we can use hot key combination Ctrl-` or Cmd-`or View \ Terminal menu item.
To see created component we can click Refresh Explorer button.
sfdx force:lightning:component:create --componentname AuraCmpHello --outputdir
force-app\main\default\aura
Create LWC
Lightning Aura Components are stored in `aura` subfolder while Lightning Web Components are stored in
`lwc` subfolder. So to create Lightning Web Component we need to click SFDX: Create Lightning
Web Component menu item on `lwc` subfolder. Let’s create lwcHello component using menu item.
Create in terminal
Lightning Aura Components are stored in `aura` subfolder while Lightning Web Components are stored in
`lwc` subfolder. So to create Lightning Web Component we need to click SFDX: Create Lightning
Web Component menu item on `lwc` subfolder. Let’s create lwcHello component using menu item.
We can notice that this command
sfdx force:lightning:component:create --type lwc --componentname lwcHello --outputdir
force-app\main\default\lwc
is executed by the Visual Studio, which looks very similar to the command used to create Lightning Aura
Components, please note the different parts: --type lwc attribute and different location ending. Let’s
use this command from terminal to create another Lightning Web Component called
helloWebComponent
sfdx force:lightning:component:create --type lwc --componentname helloWebComponent
--outputdir force-app\main\default\lwc
Metadata API LWC?
How do I retrieve Lightning Web Components using Ant Migration tool or mdapi:retrieve
command from SFDX?
What is appropriate metadata API component which corresponds to LWC folder components in sfdx?
The following XML code should be added to package.xml for Ant or force:mdapi:retrieve SFDX
command:
<types>
<members>*</members>
<name>LightningComponentBundle</name>
</types>
SFDX command
sfdx force:source:retrieve -m LightningComponentBundle
can be used as well to retrieve lwc folder.
Migrate Bundle Files
Aura and LWC have similar but different structure. Aura components have multiple Javascript files while
LWC have the only Javascript file which is also an ES6 Javascript module as we pointed in the LWC
Building Blocks section.
How can we migrate existing Aura Component Bundle Files to Lightning Web Component
structure?
Salesforce documentation provides the following table to address this question.
Moving business logic determining condition for being on the first page to the Javascript allows
developers to write unit tests for it.
Migrate Initializers
How can we migrate existing Aura Component initializers to Lightning Web Components?
Aura Initializers become lifecycle hooks. Replace an init event handler in an Aura component with the
standard JavaScript connectedCallback() method in a Lightning web component. So the following
code
<aura:handler name="init" value="{!this}" action="{!c.onInit}" />
can be translated into such code inside the Javascript file
connectedCallback() {
// initialize component
}
Migrate CSS
How can we migrate existing Aura Component CSS to Lightning Web Components?
To migrate CSS just proprietary THIS class, that Aura components use, should be removed.
This Aura CSS code snippet
.THIS .lower-third > p {
padding: 0;
}
corresponds to the following LWC CSS code snippet counterpart
.lower-third > p {
padding: 0;
}
Shadow DOM
Shadow DOM CSS
Aura component styles cascade to any Lightning web components that they contain.
However, the styles of a Lightning web component never interfere with other Lightning web components
or with Aura components. Lightning web component styles don’t cascade to their children. Overriding
styles that you don’t own can create many problems, so Lightning web components don’t allow it.
Lightning web components use a web-standard mechanism called shadow DOM that hides the elements
inside the component from the page that contains the component. Because Lightning web
components have a shadow DOM, styles defined in a component’s style sheet are scoped to the
component. They don’t apply to parent, child, or sibling components. This rule is strict, but it allows a
component to be reused in different contexts without losing its styling. It also prevents a component’s
styles from overriding styles in other parts of a page.
To make development easier for component authors, a Lightning web component’s shadow DOM works a
bit differently than the web standard. One difference is that the shadow DOM for a Lightning web
component is created automatically. The component author doesn’t have to implement it. Also, a
Lightning web component’s shadow DOM works even on browsers that don’t natively support
shadow DOM.
JS Code Reuse
In Aura framework the only way to reuse Javascript Code was creation of abstract basic component and
inheritance of it by descendants components. If a component needs to reuse code from two different
components, one of those aura components should inherited another since multiple inheritance is not
allowed in Aura framework. Lightning Web Component Javascript Module can however import as
many other modules as developers want. Also, Javascript code from Lightning Web Component can
be reused in Aura component as well.
In LWC developer needs to import the module to use methods from it while in Aura Component the
module should be included in markup and then retrieved in Javascript code.
So LWC to Aura Javascript code reuse is implemented through aggregation instead of inheritance
LWC JS Code Reuse
/*utils.js*/
export function isFunction(value) {
return typeof value === 'function';
}
/* libcaller.js */
import { LightningElement, track } from 'lwc';
import { isFunction } from 'c/utils';
export default class LibCaller extends LightningElement {
@track result;
checkType() {
// Call the imported library function
this.result = isFunction(
function() {
console.log('I am a function');
}
);
}
}
Aura JS Code Reuse
<aura:component>
<aura:handler name="init" value="{!this}" action="{!c.doInit}"/>
<p>Aura component calling the utils lib</p>
<!-- add the lib component -->
<c:utils aura:id="utils" />
</aura:component>
({
doInit: function(cmp) {
// Call the lib here
var libCmp = cmp.find('utils');
var result = libCmp.isFunction(
function() {
console.log(" I am a function");
}
);
console.log("Is it a function?: " + result);
}
})
Third-party libraries
For third-party Javascript libraries stored in static resources, global value provider was used with
ltng:require tag like following
<ltng:require scripts="{!$Resource.resourceName}"
afterScriptsLoaded="{!c.afterScriptsLoaded}" />
In LWC static resource is imported through import command
import resourceName from '@salesforce/resourceUrl/resourceName';
and then loadScript or loadStyle methods can be used to load the third-party library.
No Dynamic Create
There is no equivalent for dynamic components creation $A.createComponent() method from Aura
framework in LWC implementation. Salesforce decided deliberately not to provide dynamic
components creation equivalent since they believe that this feature has led to buggy and convoluted
code existence in Aura components and they decided not to provide this feature in LWC to avoid
buggy and convoluted code.
However, inside Aura component or app dynamic component creation can be used to create LWC
component dynamically inside an Aura component.
Apex Calls in LWC
There is one standard way to call Apex method from Aura framework
While in LWC there are three different ways how Apex can be used.
To call an Apex method, a Lightning web component can:
Wire a property
Wire a function
Call a method imperatively
In every way apex method should be imported first by using syntax
import apexMethodName from '@salesforce/apex/Namespace.Classname.apexMethodRef’;
Any Apex method to be exposed to LWC component, should be declared as static and public or global
method with @auraEnabled annotation. The first two options require Apex method to be cacheable,
which means it should be declared with @AuraEnabled(cacheable=true) annotation while imperative
Apex call can be used even if Apex method is not cacheable.
public with sharing class ContactController {
@AuraEnabled(cacheable=true)
public static List<Contact> getContactList() {
return [SELECT Id, Name FROM Contact LIMIT 10];
}
}
Wired property
The simplest way to call Apex from LWC is to use wired property.
import { LightningElement, wire } from 'lwc’;
import getContactList from '@salesforce/apex/ContactController.getContactList’;
@wire(getContactList)
wiredContacts({ error, data }) {
if (data) {
this.contacts = data;
this.error = undefined;
} else if (error) {
this.error = error;
this.contacts = undefined;
}
}
Here wiredContacts is a function and it is wired to the same Apex method.
Wired function HTML
The markup to display the data is similar but different
<template if:true={contacts}>
<template for:each={contacts} for:item="contact">
<p key={contact.Id}>{contact.Name}</p>
</template>
</template>
<template if:true={error}>
<c-error-panel errors={error}></c-error-panel>
</template>
@track contacts;
@track error;
connectedCallback() {
getContactList()
.then(result => {
this.contacts = result;
})
.catch(error => {
this.error = error;
});
}
The markup to display the data can be the same as for wired function approach
Migrate Facets
Aura framework provided facets options to dynamically insert component markup using attribute with type
of Aura.Component[]. For example, the following code could be used:
<aura:component>
<aura:attribute name="header" type="Aura.Component[]"/>
<div>
<span>{!v.header}</span><br/>
<span>{!v.body}</span>
</div>
</aura:component>
In Lightning web components, slots are used instead of the facets. To migrate body facet, it is possible to
use unnamed slot and for header it is possible to use named slot like following
<template>
<div>
<slot name="header"></slot><br/>
<slot></slot>
</div>
</template>
Populate slots
To use this component in parent, markup should be provided for slots in the following way
<template>
<c-named-slots>
<span slot="header">Header !</span>
<span>Body content</span>
</c-named-slots>
</template>
In this example, “Header !” text is passed to the header slot and span with content “Body content” is
passed to unnamed slot.
If a component has more than one unnamed slot, the markup passed into the body of the component is
inserted into all the unnamed slots. However, such UI pattern is unusual. A component usually has
zero or one unnamed slot.
Migrate Global VP
Many Global value Providers in Lightning have corresponding @salesforce Javascript module in LWC.
({
handleCustomEvent: function(cmp, evt) {
// Get details from the DOM event fired by the Lightning web component
var msg = evt.getParam('message') || '';
}
})
Testing Lightning
In Aura components, Lightning Testing Service can be used to test components.
In Lightning web components, Jest can be used for unit testing. If Jest doesn’t cover all your test cases,
use Lightning Testing Service to cover the remaining test cases. Jest unit tests can be stored in the
same source code repository but they cannot be saved to cloud and can only be run locally or by
continuous integration server machine.
Aura Methods
Aura methods can become Javascript methods. Migrate methods from <aura:method> tags in an Aura
component to JavaScript methods with an @api decorator in a Lightning web component.
More topics…
Import Objects and Fields from @salesforce/schema (object and fields references instead of string literal)
https://developer.salesforce.com/docs/component-library/documentation/lwc/lwc.apex
JavaScript Property Names (Don’t start names with on, aria, data, don’t use slot, part, is as names)
https://developer.salesforce.com/docs/component-library/documentation/lwc/js_props_names
Library component mapping (most lightning: library components are supported, for complete list visit link)
https://developer.salesforce.com/docs/component-library/documentation/lwc/lwc.migrate_map_aura_lwc_compon
Standard event mapping (use lifecycle hooks for valueInit, valueDestroy and valueRender,use hashChange
instead of aura:locationChange, use navigation service and pageReference object for force:navigate… or
lightning:openFiles or force:createRecord or force:editRecord; import ShowToastEvent from the
lightning/platformShowToastEvent module instead of force:showToast, for complete list visit link)
https://developer.salesforce.com/docs/component-library/documentation/lwc/lwc.migrate_events
Even more topics…
Navigation mixin
https://developer.salesforce.com/docs/component-library/documentation/lwc/lwc.use_navigate
Salesforce modules
https://developer.salesforce.com/docs/component-library/documentation/lwc/lwc.reference_salesforce_modules
Conclusion
As we can conclude now, Salesforce provide Lightning Web Components to be able to follow the latest
Javascript code standards and to discourage developers to use some features of Aura framework
which might lead to buggy and convoluted code. Also UI performance can be significantly increased
on modern browsers which support the latest Javascript code standards. Polyfills to older browsers
which do not support the latest code standards are also provided but they can slow down
performance on older browsers. Every Salesforce developer should learn the new features provided
by Salesforce to suggest the customers the best appropriate development option.
1.
References
https://medium.com/inside-the-salesforce-ecosystem/lightning-web-components-an-isv
2. https://salesforce.stackexchange.com/questions/243752/lightning-web-components-be
3. https://developer.salesforce.com/docs/component-library/documentation/lwc
4. https://developer.salesforce.com/blogs/2018/12/introducing-lightning-web-components
5. https://trailhead.salesforce.com/en/content/learn/projects/quick-start-lightning-web-com
6. https://salesforce.stackexchange.com/questions/250007/how-do-i-retrieve-lightning-we