Mastering Dynamic Component Loading in Salesforce LWC 🌟

Mastering Dynamic Component Loading in Salesforce LWC 🌟

For years, Salesforce developers have grappled with a significant challenge: the static nature of Lightning Web Components (LWCs). This limitation meant that developers had to predefine which components would be used, hindering flexibility and leading to bloated, less efficient applications. Often, the workaround involved cumbersome solutions like Screen Flows to achieve dynamic behavior, a far cry from the sleek, streamlined development Salesforce is known for. But no more! Salesforce has introduced a powerful feature to dynamically load LWCs, revolutionizing how we approach component customization and application efficiency. Let's dive into how this feature is changing the game. 🎲

The Dynamic Shift: Why It's a Game-Changer 🌈

Breaking Free from Static Limitations

Until now, the inability to dynamically load components directly within LWCs meant developers had to jump through hoops, using tools like Screen Flows to inject some level of dynamism into their applications. This not only complicated the development process but also limited the potential for truly responsive and adaptable applications.

Customization and Extendability for ISVs

One of the most exciting aspects of dynamic component loading is the door it opens for Independent Software Vendors (ISVs) within the Salesforce ecosystem. With this feature, ISVs can now create LWCs that are not only configurable but also extendable. This means that managed packages can offer unprecedented levels of customization, allowing customers to tailor components to their specific needs, enhancing both the functionality and user experience of their Salesforce applications. 🛠️

Preparing for the Dynamic Era 📚

Step 1: Setting the Stage

To embrace dynamic component loading, ensure Lightning Web Security is on. Only then can you proceed to the enchanting world of dynamic LWCs.
How to enable Lightning Web Security

Step 2: Configuring Your Component

Your journey begins with the declaration of the lightning__dynamicComponent capability in your component's configuration file:

<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
  <apiVersion>59.0</apiVersion>
  <capabilities>
    <capability>lightning__dynamicComponent</capability>
  </capabilities>
</LightningComponentBundle>

This simple yet powerful declaration sets the foundation for dynamic loading.

Step 3: The Syntax of Dynamism

Dynamically instantiating your LWC is now as simple as using the <lwc:component> element with the lwc:is directive:

<template>
    <div class="slds-card">
        <div class="slds-card__header slds-grid">
            <header class="slds-media slds-media_center slds-has-flexi-truncate">
                <div class="slds-media__figure">
                    <lightning-icon icon-name="utility:world" alternative-text="World" size="medium"></lightning-icon>
                </div>
                <div class="slds-media__body">
                    <h2 class="slds-card__header-title">
                        Wellcome dynamic loading of LWCs
                    </h2>
                </div>
            </header>
        </div>
        <div class="slds-card__body slds-card__body_inner">
            <template for:each={dynamicComponents}  for:item="dynamicComponent">
                <div key={dynamicComponent.key}>
                    <lwc:component lwc:is={dynamicComponent.component} lwc:spread={dynamicComponent.parameters}></lwc:component>
                </div>
            </template>
        </div>
        <footer class="slds-card__footer">
            <lightning-button label="Load another component" onclick={loadAdditionalComponent} variant="brand"></lightning-button>
        </footer>
    </div>
</template>

This is not proposed way of loading components! First load component, then use it in for loop!

And with a sprinkle of JavaScript magic :

import { track, LightningElement } from 'lwc';

export default class LwcThPocLoadLwcDynamicLoad extends LightningElement {
    @track
    dynamicComponents = [];

    connectedCallback() {
    }

    loadAdditionalComponent() {

        console.log('Starting to load lwcThPocDynamicComponent2');

        console.time("DynamicComponentImportForLoop");

        for (var i=0; i<1000; i++){
            // console.time("DynamicComponentImport2");
            import("c/lwcThPocDynamicComponent")
                .then(({ default: c }) => {
                    this.dynamicComponents.push({
                        component: c, 
                        parameters: {textToRender: `Wellcome ${this.dynamicComponents.length}`},
                        key: this.uuidv4()
                    });
                    // console.timeEnd("DynamicComponentImport2"); // Stops the timer and logs the duration
                })
                .catch((err) => {
                    debugger;
                    console.log("Error importing component");
                    // console.timeEnd("DynamicComponentImport2"); // Ensure to stop the timer even if there's an error
                });
        }
        console.timeEnd("DynamicComponentImportForLoop");

    }

    uuidv4() {
        return "10000000-1000-4000-8000-100000000000".replace(/[018]/g, c =>
          (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
        );
      }
}

You're now wielding the power to dynamically render components as if by magic.

Performance Insights: The Proof Is in the Pudding 📊

In the quest to optimize our Salesforce applications, understanding the performance implications of dynamic component loading is crucial. Let's dive into some fascinating findings from our exploration, which shed light on how dynamic imports behave in real-world scenarios.

Initial Load vs. Subsequent Loads

When I dynamically import a Lightning Web Component (LWC) for the first time, the operation is relatively more time-consuming. Based on my measurements, fetching the component initially takes around 250 milliseconds. This time frame includes the network request, server response, and the client-side processing to make the component available for use.

However, once the component is fetched for the first time, any subsequent loads are significantly faster, taking roughly 1 millisecond to resolve the dependency. This stark difference highlights the efficiency of Salesforce's caching mechanism, which ensures that once a component is loaded, it's readily available for immediate reuse without the overhead of additional network requests or processing.

The Pitfalls of Initial Loading in Loops

A particularly intriguing aspect of dynamic loading involves its behavior when attempting to load multiple instances of a component within a loop. In my tests, trying to dynamically load 1000 instances in a rapid succession (using a for loop) led to failures after the initial 25 loads. This limitation underscores the importance of cautious, strategic loading of dynamic components, especially when dealing with bulk operations. So if you'll need to load more than one instance, I suggest first resloving the import dependency, to later use that in for loop.

Rendered response where you can see lot's of errors, and only 25 components loaded.

Here's a snippet that illustrates the approach used in our experiment:

console.time("DynamicComponentImportForLoop");

for (var i = 0; i < 1000; i++) {
    import("c/lwcThPocDynamicComponent")
        .then(({ default: c }) => {
            this.dynamicComponents.push({
                component: c, 
                parameters: {textToRender: `Welcome ${this.dynamicComponents.length}`},
                key: this.uuidv4()
            });
        })
        .catch((err) => {
            console.log("Error importing component");
        });
}
console.timeEnd("DynamicComponentImportForLoop");

In this code, we attempted to dynamically load 1000 instances of a component. The operation was timed to assess performance impact, and the observed limitations highlighted the importance of managing how and when dynamic imports are triggered.

After initial load, next 1k components are loaded without problem:

Key Takeaways

  • Beware of for Loops: Attempting to load multiple instances of a component in a loop can lead to limitations and failures. This scenario underscores the need for careful planning when dynamically loading components, especially in bulk.

Conclusion 🏁

Dynamic component loading in LWC opens up a realm of possibilities for crafting interactive, responsive Salesforce applications. By following the steps and considerations outlined above, you can enhance your apps' user experience without sacrificing performance. Embrace the dynamic, but remember—great power comes with great responsibility. Happy coding! 🎉👨‍💻