I often use Script editors or Content Editor Web Parts linked to an Html file to launch a client application in SharePoint. My base approach to all these apps is to:

  • Register all the scripts as with Script on Demand
  • Call LoadMultiple passing in the Script Keys
  • Executing my JavaScript app
  • Wrapping it all in a closure

Today I was using the very excellent momentjs and moment-timezone libraries, which are super helpful when dealing with dates in JavaScript. I realised I had got inadvertently got myself into a race condition, in which I was often losing :(. The moment-timezone script would error with:

Uncaught TypeError: Cannot read property 'version' of undefined
Error: ReferenceError: moment is not defined

What I had missed was to delcare the dependency between moment.js and moment-timezone.js.

Here's an example of my client app with the fix:

<div class="myapp-wp">
    <div class="myapp-wp-panel">
    </div>
</div>
<script type="text/javascript">
    var myappWrapper = function () {
        var baseUrl = _spPageContextInfo.siteServerRelativeUrl;
        if (baseUrl.substring(baseUrl.length - 1) === "/") {
            baseUrl = baseUrl.substring(0, baseUrl.length - 1);
        }
        SP.SOD.registerSod("myapp.js", baseUrl + "/Style Library/Client Apps/myapp/js/myapp.js?rev=1");
        SP.SOD.registerSod("moment.js", baseUrl + "/Style Library/Client Apps/Common/libs/momentjs/moment.min.js");
        SP.SOD.registerSod("moment-timezone.js",
            baseUrl + "/Style Library/Client Apps/Common/libs/momentjs/moment-timezone-with-data.min.js");
        SP.SOD.registerSodDep("moment-timezone.js", "moment.js");//Moment is a dependency of moment-timezone, so register it.
        SP.SOD.loadMultiple(
            ["SP.js", "myapp.js", "moment.js", "moment-timzone.js"],
            function () {
                //... Load the app here
            });
    }();
</script>

The moral of the story is this line:

SP.SOD.registerSodDep("moment-timezone.js", "moment.js");

That let's SharePoint know that we want to load up moment.js before moment-timezone.js.