Benchmark and improve Performance of Salesforce lightning components/applications

Pavan
11 min readNov 26, 2018

--

In this post we will look at how to benchmark and improve the performance of salesforce lightning components both for the first load and for subsequent updates. We will also look on how to progressively render pages which helps in improving the perceived performance.

Section 1: The basics on how the browser renders web pages
i. Critical rendering path
ii. Web pages VS Web apps.

Section 2: Salesforce context, what is in our control and what is not
i. Things that affect performance

Section 3: Improving performance, Hands on
i. Improving page load times
ii. Improving interactions
iii. Progressively rendering the components in an application context

Section 1: The basics on how the browser renders web pages

i. Critical rendering path

Google has great resources for web development.
This post contents right from the basics and tools to measure the performance.I strongly recommend to read this through,

https://developers.google.com/web/fundamentals/performance/critical-rendering-path/

This is a free course which help you understand the basics with demo project where you will be hands on with the code

ii. Traditional web pages vs Single page apps, The shift from web pages to web apps

Traditionally it was the responsibility of the server to serve up the HTML to all the clients, this would mean wasting lot of server resources on serving HTML and not for the data, every interaction required a round trip to server to give the new HTML.

Then AJAX happened which solved this problem to some extent. Now a days we see fully fledged web apps which are called Single page apps.

The other approach, server should be responsible for the data and not to serve HTML.

Here is an article on how Single page apps work

Currently browsers are meant to render HTML really really fast,
In SPA context the idea is when the initial request goes to the server it respond with an App Bundle(Js), which gets parsed and HTML is generated and page gets rendered. Flash was one of the initial things where interactive client model was prominent, lets not get into details of flash and security around it.

Eg of an Single page App: Gmail
Loading the app takes some time, once loaded opening mails and navigating is instantaneous

Loading bar for Gmail

Section 2: Salesforce context, what is in our control and what is not

i. Visualforce and lightning, the two options

We as salesforce developers tend to operate at a abstract layer of things, where we do not give much attention about all that happens in the background to make our app run.

In salesforce we can build apps via two methods visualforce and lightning.
Lightning follows the Single page app/App bundle model.
There has been lot of marketing as lightning is quick as compared to visualforce, but in reality the we find lightning is quite slow ,why is it slow, or rather why does it feel slow.

To parse and render the HTML from the app bundle the client machines require some amount of compute resources, if you are on high end config machine its easy , but for a low config machine these feel painfully slow.
This will be 90% of enterprise user machines, And enterprise users will generally have multiple client heavy applications open like multiple browser tabs, excel sheets etc, which eat up lot of RAM.

The app bundle js might get downloaded over the network fast , but the time taken for a low end machines which parse the js the render the HTML might be more, this exactly what makes this problem difficult to identify and solve.
The sacrifice we make for page load times to have faster interactivity.

An analogy to explain App bundle model, I have read this from some place I do not remember the original author’s name, I will give the due credit once I have this information.

You visit a restaurant, you get the menu, you order, then the chef takes some time to prepare, and gets your food , you order one more item, again the food gets prepared and gets served.
For every request, the server takes some time and then responds.

VS

You visit a restaurant, the chef starts preparing all the items, so that you will get your items instantaneously once you place order.
Here it takes some time for the first request to get served, however the subsequent requests gets served almost instantaneously.

Performance implications, change in the equation

If the server response is slow, its in our control, we might rig up hardware, get more bandwidth etc etc
but in the latter model, you cant fix the client hardware, and every user will have different experience.
You cant solve this, unless all the users have latest and greatest phones with 4G speeds

Section 3: Improving performance, Hands on

In a Salesforce world, we do not have any control over the hardware salesforce uses, but we do have with our application.
Impact on performance, not in any particular order

  • Client Hardware - specs, processor, RAM
  • Software - Browsers
  • Network and bandwidth
  • Server RAM and compute
  • Resources - Images, JS, CSS
  • Process
  • Our Code

This is just not theory, I have personally followed all the listed steps at my company to improve performance of a lightning community and we saw significant reduction in page load times from 12+ seconds to under 4 seconds. (Benchmarked on HP Elite book 1040G3)

And this is not an exhaustive list, I will keep adding to this once I have better ways. The general web performance improvements always apply as the basics hardly change.

I will quote relevant salesforce documentations , blogs, YouTube videos wherever necessary

We will go with increasing dev difficulty, we will be using these tools

A look at number of resources that get downloaded

I am using chrome dev tools for this, other browser provide similar functionality.
Go to devtools, network tab, refresh your page and have a look at number of requests and number of bytes transferred,
Lesser the number of requests & bytes transferred better.

Improvements, Not in any particular order

1. Optimize images

Open your lightning app, open dev tools network panel, refresh the page and look at the type column and sort it by ascending order.
Find out the images and the size of each, for most of the web apps we can optimize images to < 30 kb, unless its high graphic immersive site, which we do not generally build on salesforce.

To optimize images, use

https://squoosh.app/

Best thing about this is, image compression is handled locally and no additional data is sent to the server , if you worry about copyright and other legal stuff. Its open source too.
In most cases the image size reduces by 99%.

2. Making long running components/Phantom components as background actions

Multiple queued foreground actions are batched in a single request (XHR) to minimize network traffic. The batching of actions is also known as boxcar’ing, similar to a train that couples boxcars together.

Foreground actions are the default. An action can be marked as a background action. This is useful when you want your app to remain responsive to a user while it executes a low priority, long-running action. A rough guideline is to use a background action if it takes more than five seconds for the response to return from the server.

Salesforce docs:

Open Salesforce community page optimiser add on, this work for internal salesforce apps as well and not just communities.

Navigate to the waterfall & actions tab and identify what actions qualify as background actions.

Waterfall tab in Salesforce community page optimiser

After you have qualified candidates for marking background actions, All you have to do is

var action = cmp.get("c.serverEcho");
// set as a background action
action.setBackground();

Setting actions to background will make the request go in parallel,
DO NOT SET all requests to background this will lead to performance degradation.

3. Set read only actions as storable/cacheable

Most server requests are read-only and idempotent, which means that a request can be repeated or retried as often as necessary without causing data changes. The responses to idempotent actions can be cached and quickly reused for subsequent identical actions

To set an action as storable/cacheable (API version> 44)

@AuraEnabled(cacheable=true)
public static Account getAccount(Id accountId) {
// your code here
}

DO NOT BLINDLY mark all actions are storable, read through, understand the consequences.
Please read through the life-cycle of storable actions.

4. Use urlEvent for internal navigation and not anchor tag <a>

Using the urlEvent for navigation preserves the app state, but if <a> tag is used, the app state is lost, and its equivalent to refresh of the page.
And using urlEvent the navigation is almost instantaneous.

 var urlEvent = $A.get(“e.force:navigateToURL”);
urlEvent.setParams({
“url”: ‘/pageName'
});
urlEvent.fire();

5. Design attributes, render static data via configuration

Often times we tend to render static data of lightning components from custom objects, and if the data doesn't change quite often it doesn't makes sense to use a custom object/fields.
For static data we can make use of design attributes which will give us enough flexibility to make changes via configuration and not do a code change.
This will save us a whole server round trip.

Use a design resource to control which attributes are exposed to builder tools like the Lightning App Builder, Community Builder, or Cloud Flow Designer. A design resource lives in the same folder as your .cmp resource, and describes the design-time behavior of the Lightning component — information that visual tools need to display the component in a page or app.

Add an aura attribute in .cmp resource and create a design resource and make sure the design attribute name matches with the name of aura attribute .


//.cmp resource
<aura:attribute name="AuraAttributeName" type="String"/>
//design resource
<design:component">
<design:attribute name="AuraAttributeName" label="Label" />
</design:component>

This attribute will be configurable via the builder interface(App builder, community builder etc)

Design attributes via the builder interface

We have enough flexibility to control the data and change whenever required.
This will save us from going to Apex, querying the db, returning and all the extra steps.
The gains are huge if you can identify and move your data from custom objects to design attributes.

6. Optimize XHR / Aura actions

Open the salesforce community page optimiser and have a look at action tab
This will tell how long the action took and what stage, this one is quite contextual, so you will be best people to analyse what can be optimized in your case. This will help in identifying what actions are taking more time.

Actions tab — Salesforce community page optimiser

7. The cost of using external CSS

The libraries like bootstrap/SLDS provide a lot of great stuff which we hardly use a 100%.
Eg: The bootstrap library has CSS for carousel etc which is not relevant in all the pages, why load extra bytes when it will never be used? You will be amazed to see the performance gains once you remove the unused CSS.

Check how much of CSS is really being used?
Chrome provides a code coverage report on how much css/js is being used by the page.

Open devtools, Ctrl+Shift+P , type in Code coverage and hit enter

Click on the reload button, and you will have the report

Code coverage report of bootstrap

As you can see the bootstrap home page has 94% of bootstrap CSS UNUSED.

The point is not to demean libraries like bootstrap, they are GREAT but we do not use them 100%.

Luckily with current tools we can shake off/remove unused CSS and keep only used/required CSS.

Use this npm package, to return only used CSS from the CSS file. Most of the times you see a reduction of the file size by 80%

And while building custom components, follow atomic design.

Separation of concerns in today's world of components is no more treating HTML, CSS, JS separately instead it should be bundled in a components

A component should be a collection of HTML, CSS, JS and a component should look the same and support the interactivity both independently and in a page context.

And do not mix up page/layout’s css in the interactive component

More on atomic design:

Talk by Cory house on: The Resuable Javascript Revolution
https://www.youtube.com/watch?v=L-fx2xXSVso

Cory house talk — The Reusable javascript revolution

7. Eliminate the need of libraries for just DOM manipulation

Stop using great libraries for just DOM manipulation, with the current state of javascript and browser support we can do most of the DOM manipulation with plain vanilla Javascript and lightning.
If you see yourself using libraries like jQuery, evaluate your case and see if you can do the same stuff without it.

You will see some amazing performance gains.

Summary

Benchmark your app, that’s the first step. Then you will have clear picture on what is taking time, what process to eliminate/change/improve.

If you cant measure it you cant improve it — Peter Drucker

I followed these simple steps at my company and initial page load from 12+ seconds reduced to under 4+ seconds

Improvements

Salesforce documentation

To sum up

  • Read the documentation, don’t just work blindly, The basics hardly change.
  • Analyse the impact of external CSS and JS,Eg: don’t use jQuery for just manipulating DOM.
  • If needed always use minified CSS and JS, and remove unused code.
  • Optimize images
  • Go to server at the last resort
  • Make use of app builder and design features, drive the behavior
  • For read only actions, make use of storable actions
  • For long running process, make use of background actions
  • Dynamically create components instead of using multiple <aura:if>
  • Don’t use <a> tags for internal navigation, make use of URL events, Using <a> tag, the whole app is refreshed, the state is lost, no benefit of having Single page app.

I will keep adding to the list once I discover more good ways….

Thanks for reading.

--

--