Recently I was chatting with Derick Bailey (he's working on some very slick Kendo UI tools - so keep your eyes peeled for that). Derick was interested in using
TL;DR - if you just want the configuration options on using RequireJS and Everlive together, jump down to "The Fix". If you'd like to understand why these configuration options are important (it's worth knowing!), read on.
No, don't worry. We're not going into the depths of the revealing module pattern, or CommonJS modules or AMD. But
Everlive has three dependencies:
!function (name, context, definition) { if (typeof module != 'undefined' && module.exports) module.exports = definition() else if (typeof define == 'function' && define.amd) define(definition) else context[name] = definition() }('reqwest', this, function () { // module code here return reqwest });
This wrapper is one possible implementation of what's referred to as a Universal Module Definition. The goal of a UMD is to provide a single JavaScript library that can play nicely in CommonJS, AMD and 'plain' Javascript environments. This entire wrapper is an immediately invoked function expression (IIFE). You can see that the name
argument that's passed in is "context
argument is whatever this
is at the time the wrapper is executed (so, the window
object, if this is run in a browser) and the definition
argument is a function that returns the actual instance of the library. The real interesting stuff, though, is the if statement inside the IIFE.
if (typeof module != 'undefined' && module.exports) module.exports = definition()
– detects for a CommonJS environment, and if detected, assigns the module's definition function output module.exports
else
of the if statement – else if (typeof define == 'function' && define.amd) define(definition)
– detects for an AMD environment, and if detected, calls define
and passes in the module definition function.else
of the if statement simply places the result of the module definition function on the context
(which is the value of this
when the IIFE executes - the window if we're in the browser).If you look closely at the entire if statement, you'll notice that the only time the
Got that? Good - let's put a bookmark there and come back to it in a second.
Since RequireJS 2.0, it's been possible to shim "traditional browser global" libraries so that you don't have
requirejs.config({ paths: { kendo : "vendor/kendo.all.min", underscore : "vendor/everlive/min/underscore.min", rsvp : "vendor/everlive/min/rsvp.min", reqwest : "vendor/everlive/min/reqwest.min", "kendo.data.everlive" : "vendor/everlive/min/kendo.data.everlive.min", Everlive : "vendor/everlive/min/everlive.min" }, shim: { "underscore": { exports: "_" }, "Everlive": { deps: ["underscore", "rsvp", "reqwest"], exports: "Everlive", } "kendo.data.everlive": { deps: ["Everlive"] } } });
In a nutshell, the above require.config
call is configuring RequireJS in our application. The paths
member maps the path to a library to the name/id by which we want to refer to it. This makes it easier for us, since typing kendo
sure beats vendor/kendo.all.min
The shim
member allows us to tell RequireJS that we have a library that isn't an AMD shim
: underscore
. The exports
property under underscore
has a value of "_"
- this tells RequireJS that the module value for underscore is the "_" member of the global object (the window, if you're in the client). From now on, if any AMD module takes a dependency on underscore (which is not an AMD lib by default), RequireJS knows to pass in window._
as the module value.
So, what happens in the above scenario when we have the following factors at play:
Any guesses?
Here's what happens:
Thankfully, we're here to save you the trouble.
It's important to note that traditional JavaScript apps (non-AMD, non-CommonJS) will not run into this problem, since reqwest only avoids putting it's reference on the window when AMD or CommonJS environments are present.
You have two options to mitigate this issue at the moment:
init
method to the shimrequirejs.config({ paths: { kendo : "vendor/kendo.all.min", underscore : "vendor/everlive/min/underscore.min", rsvp : "vendor/everlive/min/rsvp.min", reqwest : "vendor/everlive/min/reqwest.min", "kendo.data.everlive" : "vendor/everlive/min/kendo.data.everlive.min", Everlive : "vendor/everlive/min/everlive.min" }, shim: { "underscore": { exports: "_" }, "Everlive": { deps: ["underscore", "rsvp", "reqwest"], exports: "Everlive", init: function(underscore, rsvp, reqwest){ this.reqwest = reqwest; return this.Everlive; } } "kendo.data.everlive": { deps: ["Everlive"] } } });
This fix involves a slight hack, by adding init
method to our Everlive init
method, we simply place init
method).
This means that if we normally start our app like this:
// Start the main app logic. requirejs(["app"], function(app) { app.init(); });
Then, we alter it to look like this:
// Start the main app logic. requirejs(["app", "reqwest"], function(app, reqwest) { window.reqwest = reqwest; app.init(); });
Either approach is effectively doing the same thing: making
Jim Cowart is an architect, developer, open source author, and overall web/hybrid mobile development geek. He is an active speaker and writer, with a passion for elevating developer knowledge of patterns and helpful frameworks.