Skip navigation

Tag Archives: libraries

To help foster an ongoing conversation among Salesforce ISV and OEM partners — aka developers of Salesforce AppExchange apps — I started this discussion on the Salesforce ISV Partners LinkedIn group, which I encourage fellow ISV’s/OEM’s to join:

Let’s pool our thoughts – best practices for Salesforce ISV/OEM app development

One of the best practices I brought up was the need to properly “protect” or “sandbox” your application’s references to external JavaScript libraries within complex “mash-up” pages that include JavaScript code written by various other ISV’s / OEM’s / consultants / developers, as well as underlying Salesforce.com JavaScript code.

These days, more and more apps being developed on the Salesforce Platform rely heavily on external JavaScript libraries such as jQuery, jQuery UI, jQuery Mobile, ExtJS, Sencha Touch, KnockoutJS, AngularJS, Backbone, MustacheJS, Underscore, JSONSelect, etc. Leveraging these libraries is definitely a best practice — don’t reinvent the wheel! As jQuery quips, “write less — do more!” As a Salesforce consultant, I think, this is generally the goal 🙂

Problems emerge, though when multiple ISV’s include different versions of these JavaScript libraries as Global Variables within their Visualforce Pages or Visualforce Components — because whichever version is loaded last will, by default, overwrite the earlier version. This makes it very difficult to mash-up / integrate Visualforce Components or Pages from multiple ISV’s into a single page. When faced with this, a common developer response is to stop using the latest version of the external library and trying to make their code work against the earlier version of the library forcibly included in the page (perhaps by a managed Visualforce Component or embedded Visualforce Page).

Fortunately, there IS a better way to avoid this.

In a nutshell, the solution is: “protect” or “localize” your references to any external libraries, preferably in a JavaScript namespace corresponding to your managed package.

For instance, if your Salesforce application has the namespace “skuid”, you’re already going to probably have various JS Remoting functions available within the “skuid” JavaScript object that Salesforce automatically creates in pages with controllers with JS Remoting methods — and as an ISV, you are ensured of your managed app’s namespace being Salesforce-unique. So this namespace is just about the safest global variable you can use in the Salesforce world (anyone else who messes with it is being very, very naughty)

As a brief side-note, here’s how to ensure that your app’s “namespace global” has been defined before using it:

// Check that our Namespace Global has been defined as already,
// and if not, create it.
skuid || (window.skuid = {});

To protect your external library references, store a unique reference to these libraries within your namespace’s object, e.g. IMMEDIATELY after loading in an external library, such as MustacheJS,

// Load in Mustache -- will be stored as a global,
// thus accessible from window.Mustache
(function(){ /* MustacheJS 0.7.2 */ })()

// Store a protected reference to the MustacheJS library that WE loaded,
// so that we can safely refer to it later.
skuid.Mustache = window.Mustache;

Then, even if some other VF Component or Page loads in a different version of this library later on, you will still have access to the version you loaded (0.7.2)

// (other ISV's code)
window.Mustache = (function(){ /* MustacheJS 0.3.1 */ })()

// THIS code will run safely against 0.7.2!
skuid.Mustache.render('{{FirstName}} {{LastName}}',contactRecord);

// THIS code, however, would run against the latest version loaded in, e.g. 0.3.1,
// and thus FAILS, (since Mustache 0.3.1 has no render() method)
Mustache.render('{{Account.Name}}',contactRecord);

How to avoid having to use global references all the time

Some of you are probably thinking, “Great, now I have to prepend this global namespace all over the place!” Fortunately, with JavaScript, that’s not necessary. By wrapping your code in closures, you can safely keep using your familiar shorthand references to external libraries without worrying about version conflicts.

For instance, say that your application uses jQuery 1.8.2, but other Visualforce Components on the page are using jQuery as old as 1.3.2! (SO ancient… 🙂 What’s a developer to do?

Well, jQuery provides the helpful jQuery.noConflict() method, which allows you to easily obtain a safe reference to a version of jQuery immediately after you load it into your page. So, as an example, in YOUR code, you need to pull in jQuery 1.8.2:

<!-- load jQuery 1.8.3 -->
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script><script type="text/javascript">// <![CDATA[
// Get a safe reference to jQuery 1.8.3 var jQuery_1_8_3 = $.noConflict(true);
// ]]></script>

Then, to your horror, another Visualforce Component, that the customer you’re developing for has “got to have” in this same page (and which you don’t want to iframe…), has loaded in jQuery 1.3.2, but not bothered to namespace it!!! Therefore, both of the commonly-used jQuery globals (jQuery and $), now refer to jQuery 1.3.2!

Fortunately, FOR YOU, you’re safe! You got a protected reference to jQuery 1.8.3, and your code can carry on using $ without any issues, as long as you wrap it in a closure:

(function($){

   $('.nx-table').on('click','tr',function(){
       // Add "edit-mode" styles to this table row
       $(this).toggleClass('edit-mode');
   });

// Identify jQuery 1.8.3 as what we are referring to within this closure,
// so that we can carry on with $ as a shorthand reference to jQuery
// and be merry and happy like usual!
})(jQuery_1_8_3);