neuronjs
Version:
Neuron is A Full Feature CommonJS Module Manager, Dependency Graph Handler and Loader for Browsers
191 lines (153 loc) • 4.61 kB
JavaScript
// The logic to load the javascript file of a package
//////////////////////////////////////////////////////////////////////
function load_module (module, callback) {
var mod = mods[module.id];
mod.f = module.f;
mod.a = module.a;
var callbacks = mod.l;
if (callbacks) {
callbacks.push(callback);
if (callbacks.length < 2) {
load_by_module(mod);
}
}
}
// Scenarios:
// 1. facade('a/path');
// -> load a/path -> always
// 2. facade('a');
// -> load a.main
// 3. require('a');
// -> deps on a
// 4. require('./path')
// -> deps on a
// 5. require.async('a')
// -> load a.main ->
// 6. require.async('./path')
// -> load a/path
// 7. require.async('b/path'): the entry of a foreign module
// -> forbidden
var pkgs = [];
// Load the script file of a module into the current document
// @param {string} id module identifier
function load_by_module(mod) {
if (mod.d) {
return;
}
// (D)ownloaded
// flag to mark the status that a module has already been downloaded
mod.d = true;
var isFacade = mod.f;
var isAsync = mod.a;
var pkg = mod.k;
// if one of the current package's entries has already been loaded,
// and if the current module is not an entry(facade or async)
if (~pkgs.indexOf(pkg)) {
if (!isFacade && !isAsync) {
return;
}
} else {
pkgs.push(pkg);
}
var loaded = NEURON_CONF.loaded;
// is facade ?
var evidence = isFacade
// if a facade is loaded, we will push `mod.id` of the facade instead of package id
// into `loaded`
? mod.id
: pkg;
if (~loaded.indexOf(evidence)) {
if (!isAsync) {
// If the main entrance of the package is already loaded
// and the current module is not an async module, skip loading.
// see: declaration of `require.async`
return;
}
// load packages
} else {
loaded.push(evidence);
}
load_js(module_to_absolute_url(mod));
}
function module_to_absolute_url(mod) {
var id = mod.main
// if is a main module, we will load the source file by package
// neuron-builder will always build the main entry file
// as a javascript file with the '.js' extension
// 1.
// on use: 'a@1.0.0' (async or sync)
// -> 'a/1.0.0/a.js'
// 2.
// on use: 'a@1.0.0/relative' (sync)
// -> not an async module, so the module is already packaged inside:
// -> 'a/1.0.0/a.js'
? mod.k + '/' + mod.n + '.js'
// if is an async module, we will load the source file by module id
: mod.id;
return NEURON_CONF.resolve(id);
}
// ## Graph Isomorphism and Dependency resolving
//////////////////////////////////////////////////////////////////////
// ### module.defined <==> module.factory
// Indicates that a module is defined, but its dependencies might not defined.
// ### module.ready
// Indicates that a module is ready to be `require()`d which may occurs in two cases
// - A module is defined but has no dependencies
// - A module is defined, and its dependencies are defined, ready or loaded
// ### module.loaded
// Indicates that module.exports has already been generated
// Register the ready callback for a module, and recursively prepares
// @param {Object} module
// @param {function()} callback
// @param {Array=} stack
function ready (module, callback, stack) {
emit('beforeready', module_id(module) + ':' + module.g);
if (!module.factory) {
emit('beforeload', module.id);
return load_module(module, function () {
emit('load', module_id(module));
ready(module, callback, stack);
});
}
var deps = module.deps;
var counter = deps.length;
var callbacks = module.r;
// `module.r` is `[]` in origin.
// `!callbacks` means the module is ready
if (!counter || !callbacks) {
module.r = FALSE;
emit_ready(module);
return callback();
}
callbacks.push(callback);
// if already registered, skip checking
if (callbacks.length > 1) {
return;
}
var cb = function () {
if (!-- counter) {
stack.length = 0;
stack = NULL;
emit_ready(module);
run_callbacks(module, 'r');
}
};
stack = stack
? [module].concat(stack)
: [module];
deps.forEach(function (dep) {
var child = get_module(dep, module);
// If the child is already in the stack,
// which means there might be cyclic dependency, skip it.
if (~stack.indexOf(child)) {
return cb();
}
ready(child, cb, stack);
});
}
function emit_ready (module) {
emit('ready', module_id(module) + ':' + module.g);
}
function module_id (module) {
return module.main ? module.k : module.id;
}