Requirejs: dependencies loading out of order - javascript

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.

Related

How to make sure a module is loaded in NodeJS

This is a problem I faced more than one. Here is an example file structure:
app.js
folder
-- index.js
-- module1.js
-- module2.js
From app.js, the entry point of my application, I require folder/index.js. This file itself is just a loader who requires all the other files in the directory. module1.js and module2.js both define some methods I want to use eventually. They are never directly required by app.js since index.js takes care of that and adds common helper utilities and applies some transformations to these modules.
All works well if I then use some methods defined in those files from app.js after I required them. But the problem comes when a method defined in module2.js wants to use a method defined in method1.js (or vice-versa). Sometimes it will work, sometimes not (in folders with multiple files I didn't get to find out when precisely it works and when it doesn't yet).
If, from module2.js I require ./index.js and then use methods in it defined by module1.js, I sometimes get Cannot read property 'myMethod' of undefined. I assume it has to do with the order the modules are required by index.js, but I can't seem to find a solution to this common problem (other than duplicating code or not using methods of these other modules).
Is there a common solution to this problem? I tried doing something like this :
var modules = require(./index.js);
exports.myMethod = function() {
if(!modules.module1 || !modules.module1.myOtherMethod) {
modules = require('./index.js');
}
modules.module1.myOtherMethod();
};
But it doesn't to do anything, modules.module1 is still undefined.
It just sounds like module should require module2. That's the solution to module1 needing to call methods in module2.
If you're worried about many calls to require, don't. That's standard practice in every programming language I've used (in particular look at the import statements in any Java program. Java is verbose, I know, but this is correct practice.)
It's definitely bad practice to look at code in one module and have no idea where anything comes from, because the require statements are missing.
You have a circular dependency problem. Try moving some of the common functions to a third file and have module1 and module2 require it, or make sure that one of them requires the other in one way only.
Never ever require a file that requires the current file back.

RequireJS order of dependencies

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

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.

Is it possible to set not module *.js file as a dependency using require.js

We do not use require.js for implementing modules on js source, but I want to use it for tests. And there is a problem: I couldn't implement raw *.js file as a dependency for other modules. Is it possible?
I mean: load some *.js file and modules after it (to test it).
How define works
I use require.js for both implementation and tests. You can load any JavaScript file as a dependency before the execution of the module function using define.
define(["test/myTest.js", "test/anotherTest.js"], function(test1, test2) {
// perform your tests
});
How to use requirejs with asyncTests
You can also load code after the dependencies are loaded inside the module function using require. I use it with QUnit. Here is an example from my code.
First, make sure QUnit test runner is stopped by default (this will be similar with other test frameworks). This way, you can define when tests are going to run (that is after you loaded the relevant code).
QUnit.config.autostart = false
Second, you define your test as a module. The module loads the dependencies, then defines the tests, then loads the code to be tested. This will only be necessary when the code is self-executing and can not be load beforehand (in which case you could just go with define and be done with it). Here is my example using the Chaplin library (written in CoffeeScript).
define(['chaplin'], function(chaplin) {
asyncTest("publish startup complete event", function() {
chaplin.mediator.subscribe("startup~complete", function() {
ok(true, "startup~complete event fired");
});
return requirejs(['modules/startup/startup'], function() {
start();
});
});
});
The important part is the last requirejs call. It loads the code to be tested after the tests are defined.
dynamically loading dependencies
EDIT: Responding to comment
Assuming there exists a module called config that contains the configuration data. I am also assuming a certain format, so if your format is different you may make some minor changes. The principles holds true though.
define(["config"], function(config) {
// assuming config.modules is an array of all development modules,
// config.devPath is the base bath to development modules,
requirejs(
config.modules.map(function(module){
return config.devPath + module
})
, function() {
// all modules loaded, now go on
// however, no reference to modules left, so need to work with `arguments` array
});
});
However, you should know you lose the reference to your modules in the callback function.

Categories

Resources