Saturday 25 April 2015

Lightning Components and JavaScript Libraries

Lightning Components and JavaScript Libraries

The Problem

Anyone who has been following the Salesforce developer community’s work with Lightning Components closely will no doubt have read a few posts around including JavaScript libraries into components. This has more stringent security requirements, in that you have to load the JavaScript via a static resource rather than an external CDN from the likes of Google or Microsoft, but that’s not really anything to worry about, as it only adds a few minutes to development. What has been an issue is the order of library loading, and the fact that the libraries aren’t always initialised as they should be in an afterRender handler.  

Workarounds

Enrico Murro did a great job of writing this up on his blog, and produced a sample solution based on Require.js. Another solution was provided by Skip Sauls, as detailed on this Stack Exchange thread.

I wasn’t particularly keen on adding additional libraries and/or unmanaged packages, so my approach was to move the JavaScript that relied on included libraries out of initialisation functions and behind buttons that users clicked. I wasn’t particularly keen on my own solution either, but it looking for better workarounds seemed likely to be a not great use of my time, as I was convinced that there would be a native solution before long.

The Solution

And here is the native solution as of the Spring 15 release - the <ltng:require /> component. This allows you to specify the JavaScript and CSS files that your component relies on, and these will be loaded in the order that you list them.  It also provides an afterScriptsLoaded attribute that allows you to define a client-side controller to execute once everything is loaded, to carry out your initialisation processing. 

Here’s an example of where I’ve used this to load the QUnit JavaScript testing framework and the SinonJS stub/mock framework and then execute a test from the controller. First the markup that lists the required artifacts:

<ltng:require scripts="/resource/qUnitJS_1_18_0,/resource/Sinon_1_14_1"
    styles="/resource/qUnitCSS_1_18_0" afterScriptsLoaded="{!c.doInit}"/>

the controller method:

doInit : function(component, event, helper) {
	helper.runTests();
}

which is a lot less effort and/or a better user experience than the workarounds. Once again, masterful inactivity pays off!

Related

1 comment: