Note that this post was put together before the documentation for Lightning Web Components went live at
developer.salesforce. That site should be your first port for any explanation of a concept in LWC!
Salesforce have a new technology. Lightning Components look like they’re on the way out, and are being replaced with a new technology ‘Lightning Web Components’.
The reasons behind that, and the main principles behind its design are covered very nicely in this article on developer.salesforce.com.
From that we can then get to a series of examples here.
(Note: some of the code snippets used below, to illustrate points, are taken from the recipes linked above)
Now I’m a big supporter of evolution, and I love to see new tools being given to developers on the Salesforce platform, so, with a couple of hours to play with it - what’s the immediate impression?
This is an article on early impressions, based on reviewing and playing with the examples - I fully expect there to be misunderstandings, bad terminology, and mistakes in here - If you're OK with that, I'm OK with that. I admit, I got excited and wanted to post something as quickly as possible before my cynical side took over. So here it is - mistakes and all.
WOW. Salesforce UI development has grown up.
Salesforce aren’t lying when they’ve said that they’re trying to bring the development toolset up to the modern standards.
We get imports, what look like annotations and decorators, and there’s even mention of Promises. Maybe there’s some legs in this…
It’s easy to dismiss this as ‘Oh no, yet another change’, but the thing is - the rest of industry develops and improves its toolset - why shouldn’t Salesforce?
The only way to keep the product on point IS to develop the frameworks, replace the technology, upgrade, move on. If you don’t do that then the whole Salesforce Ecosystem starts to stagnate.
Or to put it another way - in every other part of the developer community, learning from what was built yesterday and evolving is seen as a necessity. It’s good to see Salesforce trying to keep up.
So what are the big things that I’ve spotted immediately?
import is supported, and that makes things clearer
Import is a massive addition to Javascript that natively allows us to define the relationships between javascript files within javascript, rather than at the HTML level.
Essentially, this replaces the use of most ‘script’ tags in traditional Javascript development.
For Lightning Web Components, we use this to bring in capabilities from the framework, as well as static resources.
E.g. Importing modules from the Lightning Web Components framework:
import { LightningElement, track } from 'lwc';
Importing from Static Resources:
import { loadScript } from 'lightning/platformResourceLoader’;
import chartjs from '@salesforce/resourceUrl/chart';
What this has allowed Salesforce to do is to split up the framework into smaller components. If you don’t need to access Apex from your web component, then you don’t need to import the part of the framework that enables that capability.
This *should* make individual components much more lightweight and targeted - only including the capabilities that are required, when they are required.
Getting data on screen is simpler
Any javascript property is visible to the HTML template.
E.g.
export default class WebAppComponentByMe extends LightningElement {
contacts;
We can then render this property in the HTML with {contacts} (none of those attributes to define and none of those pesky v dot things to forget).
Much neater, much more concise.
We track properties
Looking at the examples, my assumption was that if we want to perform actions when a property is changed, we mark the property trackable using the @track decorator.
For example:
export default class WebAppComponentByMe extends LightningElement {
@track contacts;
I was thinking that, at this point, anything that references this property (on page, or in Javascript) will be notified whenever that property changes.
However, at this point I can't really tell what the difference is between tracked and non-tracked properties - a mystery for another day
Wiring up to Apex is much simpler
One of the big criticisms of Lightning Components that I always had was the amount of code you need to write in order to call an Apex method. OK, so you have force:recordData for a lot of situations, but there are many times when only an Apex method will do.
In Web Components, this is much simpler.
In order to connect to Apex, we import the ‘wire’ module, and then import functions into our javascript
import { LightningElement, wire } from 'lwc';
import getContactList from '@salesforce/apex/ContactController.getContactList';
The first line imports the wire capabilities from the framework, the second then imports the Apex method as a javascript method, therefore making it available to the component.
We can then connect a javascript property up to the method using the wire decorator:
@wire(getContactList) contacts;
Or wire up a javascript method:
@wire(getContactList)
wiredContacts({ error, data }) {
if (data) {
this.contacts = data;
} else if (error) {
this.error = error;
}
}
When the component is initialised, the getContactList method will be executed.
If the method has parameters, that’s also very simple (E.g. wiring to a property):
@wire(getContactList, { searchKey: '$searchKey' })
contacts;
Changing the value of a property causes Apex to re-execute
Having wired up a property as a parameter to an Apex bound Javascript function, any changes to that property will cause the function to be re-executed
For example, if we:
searchKey = '';
@wire(findContacts, { searchKey: '$searchKey' })
contacts;
Whenever the searchKey property changes, the Apex method imported as ‘findContacts’ will be executed and the contacts property is updated.
Thankfully, we can control when that property changes, as it looks like changing the property in the UI does not automatically fire a change the property on the Javascript object. In order to do that, we need to change the property directly.
E.g. Let’s say we extend the previous example and there’s an input that is bound to the property, and there’s an onchange event defined:
And the handler does the following:
handleKeyChange(event) {
this.searchKey = event.target.value;
}
This will cause the findContacts method to fire whenever the value in the input is changed.
Note that it is the assignment to this.searchKey that causes the event to fire - it looks like the binding from the HTML is 1-way. I admit that I need to investigate this further.
Events do not require configuration to be implemented
Events work in a completely different way - but then that’s not a problem - Application and Component events were different enough to cause headaches previously. The model is actually much simpler.
The example in the above referenced repository to look at is ‘PubSub’.
It’s much too involved to into detail here, but the result is that you need to:
- Implement a Component that acts as the messenger (implementing registerListener, unregisterListener and fireEvent)
- Any component that wants to fire an event, or listen for an event will import that component to do so, firing events or registering listeners.
This would seem to imply that (at least a certain amount of) state within components is shared - looking like those defined with 'const'
Whatever the precise nature of the implementation, a pure Javascript solution is surely one that anyone involved in OO development will welcome.
I suspect that, in a later release, this will become a standard component.
Summary
Some people will be thinking "Man, glad I didn’t migrate from Classic / Visualforce to Lightning Experience / Components - maybe I’ll just wait a little longer for it all to settle down”.
You’re wrong - it won’t settle, it’ll continue to evolve and the technologies will be continually replaced by new ones. Eventually, the jump from what you have to where you need to get to will be so huge that you’ll find it incredibly hard. There’s a reason why Salesforce pushes out 3 releases a year, whether you want it or not, these technology jumps are just the same. The more you put it off, the more painful it’ll be.
The change from Lightning Components to Lightning Web Components is vast - a lot more than a single 3 letter word would have you suspect. The only real similarities between the two frameworks that I’ve seen up to now are:
- Curlies are used to bind things
- The Base Lightning Components are the same
- You need to know Javascript
Other than that, they’re a world apart.
Also, I couldn’t find any real documentation - only examples - although those examples are a pretty comprehensive starting point.
Now, obviously it's early days - we're in pre-release right now, but what I've seen gives me great hope for the framework, it's a significant step forward and I can't wait to see what happens next. I wonder if a Unit Testing framework might follow (I can but hope)
You could wait, but hey, really, what are you waiting for? Come on, jump in. The change is exciting...