Widget boilerplate and external libaries loading

7
Some time ago I attended the Widget workshop at Mendix. Something that I'm currently struggling with is related to loading jQuery and other external libraries without running into conflicts. Looking at the AppStoreWidgetBoilerplate and several widgets on the Mendix github, I see different methods of loading external libraries. Something that can cause issues is loading an external library (ie jQuery) several times incl. several different versions. One loads jQuery as a package(calendar widget) and puts $ in the function declaration (does not use noConflict(true)). Another (boilerplate) uses define with jquery file, declares _jQuery and then assigns $ with jQuery.noConflict(true). I'm looking for a foolproof (as much as this is possible) method of loading external libraries, of which jQuery seems a good example without running into mulitpleDefine issues or missing libaries. Ie Calendar widget loads jQuery, then loads fullcalendar, which checks for jQuery (but which one, global or in scope??) and same goes for momentJs. Additionally I see the boilerplate using define to instantiate a widget and several widgets using require. In what way is define usable in the context of Mendix widgets? When would one choose one or the other? Also when we try to use this type of widget initialization, we run into issues with external libraries not finding other external libraries, as fullcalendar relies on momentJs. If someone could help me out, much appreciated!
asked
4 answers
3

jquery is a nasty piece of work in that it tries to conform to the AMD spec but does so by using a non-uniqe identifier, "jquery" to define itself (search for the string "define(" in an uncompressed jquery version and you'll see).

This leads to your problem where loading multiple jquery versions, even with the noconflict method, will invariably fail/lead to unpredictable behavior.

The cleanest way we've been able to come up with is to edit the jquery source, by removing the "jquery" parameter string from the call to define. This changes the define to defining the path, which should always be unique.

For jquery 1.11.3:

if ( typeof define === "function" && define.amd ) {
    define( "jquery", [], function() {
        return jQuery;
    });   
}

becomes:

if ( typeof define === "function" && define.amd ) {
    define([], function() {
        return jQuery;
    });   
}

(edited: wrapper method still doesn't solve the problem 100%)

answered
3

So, this actually took us a long time to pinpoint and figure out, but, here's the lowdown: define and require 'look' identical and perform very similar things but are in fact very different beasts and should be used for different reasons.

define says: "I am defining a module, and I will only be evaluated and available when all of my dependencies have been successfully loaded"

require says: "load these modules first, then run me"

So what's the difference? require basically says: "run me someday when you have time and all of my dependencies have been run". define says: "I will load these modules and myself if someone nee ds me".

Ergo, the correct way of structuring a javascript app is to have one central "entrypoint" require that loads the entire app. This require statement should depend on everything it needs, includi ng all sorts of other modules that should be setup via defines that depend on other things.

This is how AMD was intended to be used.

In a mendix app, there's already an entrypoint require in mxui/mxui, which depends on widgets.js, which loads all of your custom widgets.

You could theoretically get away with using requires in these custom widgets, but you run the very real risk of those widgets not loading correctly due to asynchronous issues (most notably on mobile platforms).

So please, think of the children, use define ;)

answered
0

Andries has provided an answer for the jQuery conflicts

The jQuery NoConflict() is a JQuery solution for multiple jQuery versions. I prefer to load jQuery with dojo require and scope it with a local variable.

With define you register a module in require.js that you than can depend on in other module definitions or require statements. With require you "just" load/use a module or javascript file that can be loaded by require.js.

Define: If you want to declare a module other parts of your application will depend on.

Require: If you just want to load and use stuff.

answered
0

Ok, so define it is. I will have a look at what Achiel proposes for jQuery modification.

Btw; I tried the solution Andries proposes, but this involves changing any external libraries that depend on jQuery as those libraries always refer to jQuery or $ and not the aliased versions.

answered