src/require.js
// Load up and invoke our modules along with all of their dependencies. This function will first find all dependencies
// for our modules and then attempt to load and invoke them from least to most dependent. This procedure needs to
// happen in 2 separate operations due to the possibility of anonymous modules having their own dependencies that we
// don't actually know about until after we've loaded it's file.
/* eslint-disable */
var require = function() {
/* eslint-enable */
// Fetch and normalize the argument that were passed in.
var args = me.amd.args(arguments, require.args.router, require.args.normalize, {
error: null,
deps: null,
factory: null
});
// Boot up our dependencies.
require.boot(args.deps, function() {
// At this point all of our dependencies have loaded, now we need to go ahead and invoke all of our dependencies in
// an order from least to most dependent, that way our initial `require` being requested can be invoked.
require.invoke(args.deps);
// Invoke our `factory` function with it's required dependency references.
me.module.invoke.factory(args.factory, args.deps);
}, args.error);
};
// Load up all of our dependencies, along with any nested dependencies in the order of least to most dependent.
require.boot = function(modules, successCallback, errorCallback) {
// If our `deps` argument was malformed or empty, invoke our callback and halt the function.
if (!me.isaArray(modules) || !modules.length) {
successCallback();
return;
}
// Boot up our anonymous modules first. If we're booting, halt the function and we'll loop back around.
if (require.boot.anonymous(modules, successCallback, errorCallback)) {
return;
}
// Boot our dependencies.
require.boot.dependencies(modules, successCallback, errorCallback);
};
// Check to see if there's any anonymous modules waiting to be loaded, if there is, then we'll load them.
require.boot.anonymous = function(modules, successCallback, errorCallback) {
// Store our anonymous module that we need to load.
var queue = require.boot.anonymous.queue(modules);
// If we have any anonymous modules that we need to load, do it now, then loop back around.
if (queue.length) {
require.loop(queue, modules, successCallback, errorCallback);
// Explicitly return `true` so that we don't halt the loop.
return true;
}
// By returning `false` we'll halt the anonymous module loop check.
return false;
};
// Check to see if we have any dependencies which are anonymous modules that've yet to be loaded.
require.boot.anonymous.queue = function(modules) {
// Store our queue of anonymous modules.
var queue = [];
// Loop through and fetch our dependencies.
me.each(modules, function(moduleName) {
// Reference our module definition.
var module = me.module(moduleName, null, false);
// If our module doesn't exist, then it's a anonymous module that we need to load up first to find out what
// dependencies are actually required for it.
if (!module) {
// Push the module off to our anonymous list.
require.anonymous.push(moduleName);
// Setup the configuration for our anonymous module.
require.config(moduleName);
// Push the module off to our queue.
queue.push(moduleName);
// Don't pass this point, as we can't figure out the dependencies for our module yet.
return;
}
// Loop and find any dependencies that are anonymous modules as well and queue them.
queue = queue.concat(require.boot.anonymous.queue(module.deps));
});
// Return all of our queued anonymous modules.
return queue;
};
// Load up all of the dependencies for the modules that are passed in.
require.boot.dependencies = function(modules, successCallback, errorCallback) {
// Fetch all of the dependencies for our modules.
var dependencies = me.module.dependencies(modules);
// Loop around until we find the start of our dependency tree.
if (dependencies.length) {
// If we have dependencies, we're not at the start of the tree, keep looping around.
return require.boot(dependencies, function() {
// Load the modules.
require.module(modules, function() {
// Fetch the dependencies for our modules again.
var newDependencies = me.module.dependencies(modules);
// Determine if there are any new dependencies, since we've loaded our set of modules.
if (newDependencies.join() !== dependencies.join()) {
// Load up our new dependencies.
return require.boot(newDependencies, function() {
// Loop back around to see if any new dependencies have loaded from our set of newly loaded dependencies.
require.module(modules, successCallback, errorCallback);
});
}
// If we didn't have any new dependencies, then run our callback.
successCallback();
}, errorCallback);
}, errorCallback);
}
// Load the start of our dependency tree.
require.module(modules, successCallback, errorCallback);
};
// Route and normalize the arguments that are passed into our `require` function. The arguments for our `require`
// `Function` can be sent in a number of different forms.
require.args = {};
// Normalize the arguments payload.
require.args.normalize = function(payload) {
// Normalize the `error` `Function`.
payload.error = me.normalizeFunction(payload.error, function() {});
// Normamlize the `dependencies` `Array`.
payload.deps = payload.deps ? me.normalizeStringSeries(payload.deps) : null;
// Normalize the `factory` `Function`.
payload.factory = me.normalizeFunction(payload.factory);
// Return the noramlized `payload`.
return payload;
};
// Route the arguments passed into the `require` `Function`.
require.args.router = [];
// Handle no arguments being passed into the `require` `Function`.
require.args.router[0] = function(args, payload) {
// Throw an error to the end user.
me.log(1, 'require', 'args', 'No arguments were passed into `require`! Halting!', args);
// Return our factored payload.
return payload;
};
// Handle 1 argument being passed into the `require` `Function`.
require.args.router[1] = function(args, payload) {
// If it's a `Function`, derive our dependencies from it.
if (me.isFunction(args[0])) {
// Reference the factory.
payload.factory = args[0];
// If it's an `Array` or `String` it's the `dependencies`.
} else if (me.isaArray(args[0]) || me.isString(args[0])) {
payload.deps = args[0];
// If none of the criteria above matched, then the arguments are malformed.
} else {
me.log(1, 'require', 'args', '1 argument was passed into `require` that was malformed! Discarding!', args);
}
// Return our factored payload.
return payload;
};
// Handle 2 arguments being passed into the `require` `Function`.
require.args.router[2] = function(args, payload) {
// If both arguments are a `Function` then treat them as the `factory` and `error` callbacks.
if (me.isFunction(args[0]) && me.isFunction(args[1])) {
// Reference the `error` `Function`.
payload.error = args[1];
// Reference the `factory` `Function`.
payload.factory = me.normalizeFunction(args[0]);
// Otherwise treat the arguments as the `dependencies` and `factory`.
} else if (me.isaArray(args[0]) || me.isString(args[0])) {
// Reference the `dependencies`.
payload.deps = args[0];
// Reference the `factory`.
payload.factory = args[1];
// If none of the criteria above matched, then the arguments are malformed.
} else {
me.log(1, 'require', 'args', '2 arguments were passed into `require` that were malformed! Discarding!', args);
}
// Return our factored payload.
return payload;
};
// Handle 3 arguments being passed into the `require` `Function`.
require.args.router[3] = function(args, payload) {
// Reference the `dependencies`.
payload.deps = args[0];
// Reference the `factory`.
payload.factory = me.normalizeFunction(args[1]);
// Reference the `error`.
payload.error = me.normalizeFunction(args[2]);
// Return our factored payload.
return payload;
};
// List of anonymously required modules.
require.anonymous = [];
// Configure an anonymous module with a path and definition.
require.config = function(moduleName) {
// If we don't have a `moduleName`, then the invocation was malformed. Halt the function.
if (!moduleName) {
return false;
}
// Create our `Object` that we'll pass to our configuration `Function`.
var config = {
libs: {}
};
// Set our URL to be relative to our configurations `base` variable.
config.libs[moduleName] = {
amd: true,
urls: moduleName
};
// Pass the anonymous module over to our configuration to generate the module and URLs.
me.config(config);
};
// Assumes that all depdendencies being passed into the `deps` parameter have already been loaded. The sole purpose of
// this `Function` is to simply invoke the factories for each of the dependencies if they haven't already been invoked.
require.invoke = function(deps) {
// Fetch any dependencies of our dependencies.
var dependencies = me.module.dependencies(deps, true);
// Reverse our dependency list as our fetcher method loops through finding most to least dependent, we actually need
// to invoke each `factory` from least to most dependent.
dependencies.reverse();
// Append our initial dependencies to the bottom of our list to be invoked last.
dependencies = dependencies.concat(deps);
// Loop through each of the dependencies in our list that we need to invoke.
me.each(dependencies, function(dependency) {
// Invoke our dependency.
me.module.invoke(dependency);
});
};
// Load up a queue of modules, then run `require.boot` to check and make sure all modules along with their dependencies
// have successfully loaded. This `Function` is being to used to exhaust all dependencies. In the case of anonymous
// modules, we may load up a file and find out we have new dependencies that must be loaded, this `Function` is taking
// care of that.
require.loop = function(queue, modules, successCallback, errorCallback) {
// Load any modules in our queue.
require.module(queue, function() {
// Run back to `require.boot` and attempt to boot up the modules originally requested.
require.boot(modules, successCallback, errorCallback);
}, errorCallback);
};
// Load up an `Array` of modules simultaneously.
require.module = function(modules, successCallback, errorCallback) {
// If we have no `modules`, then invoke our callback and halt the function.
if (!me.isaArray(modules) || !modules.length) {
successCallback();
return;
}
// Store an `Array` of functions that we'll run simultaneously.
var queue = [];
// Loop and queue each of our modules.
me.each(modules, function(moduleName) {
// Push our anonymous `Function` off to our parallel queue.
queue.push(function(callback) {
// Load the module.
me.module.boot(moduleName, callback, callback);
});
});
// Invoke the queue along with the callback handler.
me.parallel(queue, function() {
require.module.callback(modules, successCallback, errorCallback);
});
};
// Handle the callback after loading modules to check if there were errors.
require.module.callback = function(modules, successCallback, errorCallback) {
// Store any errors in this `Array`.
var errors = [];
// Loop through each of modules and see if there were any errors.
me.each(modules, function(moduleName) {
// Fetch a reference of the module.
var module = me.module(moduleName);
// If there's no successful, but there are failed URLs, then the module failed to load.
if (!module.loader.success && module.loader.failed.length) {
errors.push({
module: moduleName,
message: 'Failed to load.'
});
}
});
// If we have errors, fire off our error callback.
if (errors.length) {
return errorCallback(errors);
}
// Fallback on our success callback.
successCallback();
};
// Reference the module within the library.
me.require = require;