RequireJS order of dependencies - javascript

if you have a RequireJS module like so:
define(
[
'#patches',
'backbone',
'underscore',
'react',
'#allCollections',
'#allModels',
'app/js/routers/router',
'#allTemplates',
'#allControllers',
'#allRelViews'
],
function(){
var patches = arguments[0];
});
is there any way to know which dependency gets loaded first? In my case, '#patches' is a few window.X utility functions that I want to load before anything else. Do I need to configure this a different way to ensure this?
(in my case "#' is just my own notation to denote a module whose path is predefined in my main config file)

From the documentation : http://requirejs.org/docs/api.html#mechanics
"RequireJS waits for all dependencies to load, figures out the right order in which to call the functions that define the modules, then calls the module definition functions once the dependencies for those functions have been called. Note that the dependencies for a given module definition function could be called in any order, due to their sub-dependency relationships and network load order."
I think this may help: http://www.sitepoint.com/understanding-requirejs-for-effective-javascript-module-loading/ (see "Managing the Order of Dependent Files")
RequireJS uses Asynchronous Module Loading (AMD) for loading files. Each dependent module will start loading through asynchronous requests in the given order. Even though the file order is considered, we cannot guarantee that the first file is loaded before the second file due to the asynchronous nature. So, RequireJS allows us to use the shim config to define the sequence of files which need to be loaded in correct order. Let’s see how we can create configuration options in RequireJS.
requirejs.config({
shim: {
'source1': ['dependency1','dependency2'],
'source2': ['source1']
}
});
Hope it helps
EDIT: As said in comments, using Shim for AMD module is a bad idea, use only shim for non AMD modules and manage dependencies order there.
For AMD module requirejs will manage the order of loading.
A good link from the comments (thanks Daniel Tulp) ==> Requirejs why and when to use shim config

Related

Requirejs: dependencies loading out of order

So i have a couple of javascript files that I want to be ran in a specific order, and instead of doing script tags in the html page, I'd like to use requirejs so that I can modularize code. Before I started modularizing with define blocks and start refactoring code, I wanted to just set up the dependency ordering. So I have the files like this
index.html
<script src="scripts/depends/require.js"></script>
<script>
(function(){
require(['scripts/main.js', function(){}]);
}());
</script>
main.js
require(['scripts/services/fileLoader.js', 'scripts/services/Options.js'], function(){
// do stuff
});
fileLoader.js
require([
'scripts/services/alert.js',
'scripts/services/game.js',
'scripts/services/parser.js',
'scripts/services/options.js'
], function() {
// do stuff
});
Now it's pretty obvious what I want here. I want the main to invoke fileLoader.js, and then I would like fileLoader.js to invoke each of its dependencies before it invokes its callback. Then when fileLoader.js has finished its callback then I would like for main to finish its dependencies similarly before finally invoking its callback last, which is what I thought requirejs did.
However here is what happens. Main calls require and I can see that fileLoader.js and options.js are loaded. But then before any of the dependencies needed by fileLoader are invoked (nor its own callback which needs to be run for main to run correctly), the main.js callback is invoked. What is going on?
tl;dr - main callback called before dependency's callback, why?
The issue is that you are using require where you should use define and you have not passed the configuration option enforceDefine: true to RequireJS. You should always run RequireJS with enforceDefine: true unless you can cite an overriding reason not to. Without it, if RequireJS loads a module without a define in it, it will just shrug and move on. And you get the behavior you are getting.
The problem is that only define defines modules, require won't do. So if there is no define call in a module file, RequireJS does not know what the module actually depends on. It will schedule the loading of the modules listed in the dependencies of the require call but they are not taken to be dependencies of the module which would be defined in the file.
So in main.js replace the top level require with define. In fileLoader.js too, and in all other modules you want to create.
Also, do not put .js at the end of module names. RequireJS does it for you. If you do put it, you'll get unexpected results. It is not a cause of your problem here but it could be a factor in other circumstances.

Predefining AMD module dependencies in RequireJS config

For the sake of loading times, I'm interested in predefining all AMD module dependencies. This is because at the moment, the module file must load before require.js can work out its dependencies. Here's an illustration to show what I mean:
Is there any way to do this with require.js? I know you can define dependencies for the shimmed modules, but can you do this for your own custom AMD modules?
You are looking for something you can put in the configuration you pass to RequireJS that would do what you want. There is no analogue to shim for modules that call define. However, what you could do is add the deps option to your configuration:
deps: ['module', 'dep1', 'dep2', 'dep3']
This will tell RequireJS to start loading immediately your module and the dependencies. You will have to maintain this list yourself but this would be true with shim too.
Otherwise, you can do what kryger suggested in a comment: use r.js to build module into a single bundle that contains it and all of its dependencies. Whenever module is loaded, all of its dependencies are loaded at the same time. This is more efficient than using deps but might make things slightly more complicated if you ever need to load any of the dependencies by themselves. You'd have to use the runtime option bundles to tell RequireJS where these modules are. And just like deps you'd have to maintain this list yourself.

How can I load non-AMD dependencies in the defined order with dojo?

I try to make a non-AMD library loadable with dojo, I've chosen a separate folder as a new (pseudo) AMD-package and placed the files of that library in that folder, together with the main.js file, which will get loaded by convention by the dojo loader when the package is requested. In this main.js file I simply put the names of my library files in the dependency list of the define() call.
define([
"jquery",
"./lib/jquery-ui/jquery-ui.min",
"./the.actual.library.that.uses.the.others",
], function () {
return window.someGlobalSetByTheLibrary;
});
The problem with this is: the loading order of that dependencies depends on the network latency, it is not guaranteed to be the order they appear in the define().
That causes (sometimes) an error because the actual library file needs its own dependencies to be loaded first.
Dojo has a perfect means to help yourself: loader plugins.
You can write your own sequential loading plugin that ensures the loading order for you.
(For copyright reasons of corporate owned code I can not post the implementation here, but it's quite easy using dojo's Deferred and Promise to chain one loading request after the other, internally using require() to do the actual loading).
Let's assume, your dojo loader plugin has the module id myPackage/sequentialLoading.
Then, your main.js will look like this.
define([
"myPackage/sequentialLoading!jquery",
"myPackage/sequentialLoading!./lib/jquery-ui/jquery-ui.min",
"myPackage/sequentialLoading!./the.actual.library.that.uses.the.others",
], function () {
return window.someGlobalSetByTheLibrary;
});

How can you ensure that angular module dependencies get resolved?

Angular's documentation on modules (http://docs-angularjs-org-dev.appspot.com/guide/module) says:
Dependencies
Modules can list other modules as their dependencies.
Depending on a module implies that required module needs to be loaded
before the requiring module is loaded. In other words the
configuration blocks of the required modules execute before the
configuration blocks or the requiring module. The same is true for the
run blocks. Each module can only be loaded once, even if multiple
other modules require it.
I created this example (http://jsbin.com/IRogUxA/34/edit) which creates a controller module that depends on two "mid-level" modules, each of which depend on two "low-level" modules. So, I have two "mid-level" modules and four "low-level" modules.
Clearly, order does not matter in the JS source. In the example above I've defined the high level modules before the low level ones they reference. I understand that Angular makes use of dependency injection to wire up the dependencies, but the way it does so is mysterious to me.
My question: How does one ensure that the config blocks of the various modules are run in the proper order? Or more broadly, how is it that Angular can resolve all of my dependencies when they are defined in any order I choose (within the JS source code)?
All the angular module API methods, such as "config", "factory" etc, are wrapped in a "invokeLater" function. In another word, when the dependency module is evaluated, the module.config, module.factory etc are not really called at that time. Instead those invocations are simply pushed into a queue.
Consider this example:
var demo = angular.module('demo', ['module1']);
demo.config( function( ) {
console.log("In app.config")
} ).run(function(){
console.log("Angular run");
});
angular.module("module1", []).factory('myservice', function(){
return {};
}).controller('mycontroller', function(){} );
For each module it has its own queue: (for the main module "demo")
var invokeQueue = [];
invokeQueue.push("demo.config", xxx);
invokeQueue.push("demo.run", xxx);
For module1:
var invokeQueue = [];
invokeQueue.push("module.factory", xxx);
invokeQueue.push("module.controller", xxx);
Once all the scripts are loaded and DOMContentLoaded event is fired , angular starts actually load/eval all the modules. At this time angular already constructed a full module dependency tree. The dependency module is always loaded first before the main module so in this case module1 will be loaded first and it's invokeQueue is called in the original order(module.factory, module.controller etc). Then back to the main module demo's invokeQueue, demo.config, demo.run
I think it helps to think of modules as their own applications, not relying on ordering of other (external) dependencies.
If order is important, then you can introduce a module that simply composes other modules and coordinates their interactions.
We avoid taking hard module references in our angular.module({moduleName},[deps]) calls, preferring to have those rolled up by a higher level module. That makes testing in isolation lots easier and you can stub out the services you rely on with lighter weight.

Loading jQuery plugins using RequireJS -- jQuery undefined intermittently even after specifying deps?

I am attempting to load jQuery.jstree through RequireJS. You can see the exact source of the plugin here: https://gist.github.com/MeoMix/7882144
As I understand it, jQuery.jstree has three dependecies: jQuery, jQuery UI, and jQuery.cookie.
I begin with by loading my RequireJS shim config and then call an initial 'require' to kick things off:
require.config({
// Set the base URL to the Scripts directory of CSWeb
baseUrl: '/csweb/Scripts/',
shim: {
'jquery-ui': ['jquery'],
'jquery.jstree': ['jquery', 'jquery-ui', 'jquery.cookie'],
'jquery.cookie': ['jquery']
}
});
Here, I define my base URL relative to the root of my JavaScript files. The file jquery.js is located at the baseUrl. I also define dependencies for both plugins. Note: I have tried playing around with more explicit shim declarations including defining exports. I noticed no difference in effect.
After defining my config, I call:
require([
'jquery',
'jquery-ui',
'jquery.cookie',
'jstree/jquery.jstree'
], function () {
'use strict';
});
Doing so yields an error intermittently. Clearly an async-loading issue. The error reads:
Uncaught ReferenceError: jQuery is not defined jquery.jstree.js:978
Line 978 of jquery.jstree is simply where jQuery is passed into the closure to begin initialization of the plugin:
// 978 jquery.jstree.js: })(jQuery);
What am I not understanding here? I don't seem to experience this issue with most of my plugins. Is there something especially crappy about how this jstree plugin was written such that it is giving RequireJS fits? Or am I not understanding a core mechanic of RequireJS shim configuration?
UPDATE 1: It appears that it is something to do with the fact that I load jquery.jstree from a path. If I load another, empty file (jstree/jquery.test) -- I am able to replace the issue. However, if I then move test up a directory such that it is level with the other plugins -- it all loads fine.
The whole path you give to the shim configuration has to match the whole path of the module you require.
You name the shim jquery.jstree but you require it as jstree/jquery.jstree, so RequireJS does not use the shim and thus does not know that the plugin depends on jquery, etc. and so you get intermittent errors.
For things like plugins that I might want to use globally, I prefer to give them a well-known name that I can use throughout my application without worrying about paths. So in your case, I'd fix the problem by adding this to my config:
paths: {
"jquery.jstree": "jstree/jquery.jstree"
}
and I would then require it jquery.jstree.

Categories

Resources