The difference between Lightning Components and Lightning Web Components, Part 2, JavaScript and Modules

Posted by

Welcome to Part 2 of the four part series covering the difference between Lightning Components and Lightning Web Components. If you missed Part 1, I would recommend reading if you have the time, however I am trying to make these parts as modular (ha! get it?) as possible, so covering Part 1 (Markup and CSS) is not required for this read. The overall goal of this series is to help developers become better acclimated and comfortable with using Lightning Web Components in their daily practice. JavaScript is my love language and since I could easily go off the rails and rant forever on the subject, I am going to stick strictly to how it differs. Rest assured that I will be covering more JavaScript related material in later blogs. I am really excited that you are here learning with me. Let’s get started.

  • Part 1: Markup and CSS
  • Part 2: JavaScript and Modules
  • Part 3: Salesforce Data and the @wire decorator
  • Part 4: Composition and Events

When writing Lightning Components, the JavaScript structure existed in three different files: Controller.js, Helper.js and Renderer.js.

// Controller.js
({
    onInit : function(component, event, helper) {
        helper.executeInitFunction(component);
    }
})
// Helper.js
({
    executeInitFunction : function(component) {
        // execute all necessary initialization functionality
    }
})
//Renderer.js
({
    afterRender : function (component, helper) {
        // interact with DOM tree after framework’s rendering 
    }
})

A JavaScript file in Lightning Web Components is an ES6 module, which means that you are using standard JavaScript rather than the formatting above. In Lightning Web Components, you simply have a exampleName.js file that holds all of your code. This is important to note whenever you are tasked with migrating your Lightning Component code over to a Lightning Web Component. More on that later.

// Lightning Web Component JS Module
import { LightningElement, track } from 'lwc';
export default class myLightningWebComponent extends LightningElement {
    @track property;

    connectedCallback() {
        this.executeInitFunction();
    }

    executeInitFunction() {
        // execute all necessary initialization functionality
    }
}

That’s cool and all, but what does it actually mean? Lets break it down line by line.

  • LightningElement is the base class for Lightning web components which we import from lwc
  • lwc is the core module for Lightning web components. Our important statement above says that the JavaScript uses the LightningElement and track functionality from the lwc module.
  • The export statement defines a class that extends the LightningElement class.
  • As previously discussed in Part 1, connectedCallback is a life cycle hook method that is called when the component is injected into the DOM, or on load of the component. This should be compared to the onInit functionality in Lightning Components.
  • The .this keyword refers to the context object in which the current code is executing. For anyone who still has questions about .this, this blog post has a fantastic and clear explanation.

Sharing Code in Lightning Components and Lightning Web Components

To share code between the two, we want to use an ES6 module. Whenever I started reading through documentation, I saw lots of phrases like “setting up modules is easy” or “creating a module is simple” and sometimes thats not the case for everyone, so let’s walk through some of the steps. When you set up your VSCode environment and create your project, you’ll have the directory path force-app/main/default/. This is where you will find your aura and lwc folder. Typically, I always run this command when creating Lightning Web Components:

 sfdx force:lightning:component:create --type lwc -n <nameOfYourLWCHere>

This will create the three necessary files you need to get started: file.html, file.js, and file.js-meta.xml. For creating a module, we generate the exact same folder structure, except we do not need the .html file. Here is an example of a utility JS module for use in a Lightning Component and Lightning Web Component:

// utils.js
export function messageToShow(value) {
    switch (value) {
        case 0: 
            return 'This is the first element';
            break;
        case 1: 
            return 'This is the second element';
            break;
        default : 
            return 'This is the default';
      }
}
// Lightning Web Component JS Module
import { LightningElement, track } from 'lwc';
import { messageToShow } from 'c/utils';
export default class myLightningWebComponent extends LightningElement {
    @track result;

    connectedCallback() {
        this.executeInitFunction();
    }

    executeInitFunction() {
        // execute all necessary initialization functionality
        this.result = messageToShow(1);
        console.log('what is the result? ', this.result); //This is the second element
    }
}

The myLightningWebComponent imports the utils module and calls the methodToShow function exported by the module. The argument passed into the function is a value of 1 and therefore when the case statement evaluates, it will return ‘This is the second element’. Let’s take a look at what this looks like for calling a module from a Lightning Component:

<!--myLightningComponent.cmp-->
<aura:component implements="flexipage:availableForRecordHome, flexipage:availableForAllPageTypes" access="global">
    <aura:handler name="init" value="{!this}" action="{!c.doInit}"/>
    <c:utils aura:id="utils"/>
</aura:component>
// myLightningComponentController.js
({
    doInit : function(component, event, helper) {
        var utils = component.find('utils');
        var result = utils.messageToShow(0);
        console.log("What is the result " + result); // 'This is the first element'
    }
})

myLightningComponentController.js uses component.find(‘utils’) to match the aura:id in the markup to have reference to the module. From here, we use the variable to invoke the method and pass in our argument of 0, which after the case statement evaluates, will return ‘This is the first element’.

The option to write modules to interact with both Lightning Components and Lightning Web Components is a game changer when the inevitable architectural discussions start to happen on what to leave and what to convert. Of course, its always important to identify which situations this is most appropriate for and discuss it, however this functionality has the potential to drastically reduce scope when writing for both.

Please let me know if you have any questions or comments! My code will always be available on my GitHub profile. As always, thank you so much for taking the time to read and I am looking forward to writing the material for Part 3: Salesforce Data and the @wire decorator.

3 comments

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s