Created
May 20, 2013 03:43
-
-
Save nateabele/5610305 to your computer and use it in GitHub Desktop.
A simple, naïve, and hacky proof-of-concept for auto-loading modules in AngularJS.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Naive AngularJS module autoloader; depends on require.js. | |
* | |
* Usage: | |
* | |
* angular.autoLoad({ | |
* 'ngResource': '/js/angular-resource-1.0.1.min.js', | |
* 'google-maps': '/js/angular-google-maps.js', | |
* 'ui.bootstrap': '/js/ui/ui-bootstrap-custom-tpls-0.4.0.min.js', | |
* 'module.split.over.multiple.files': ['/js/file1.js', '/js/file2.js'] | |
* }); | |
* | |
* Then initialize your modules with their dependencies as normal, and the correct scripts will be | |
* autoloaded appropriately. | |
* | |
* Notes: | |
* As mentioned, this is currently implemented with required.js. It should be rewritten using $q. | |
* ALSO, Angular must be boostrapped manually (http://docs.angularjs.org/guide/bootstrap) *after* | |
* your autoload configuration is initialized, and *before* your application modules are loaded. | |
*/ | |
(function(angular) { | |
var _module = angular.module, _bootstrap = angular.bootstrap, _requests = 0, _inited = false; | |
var _loadMap = {}, _invokeQueue = {}, _loaded = {}, _funcCache = {}, _ = {}; | |
var _appendAndFlatten = function(list, item) { | |
if (!angular.isArray(item)) { | |
if (list.indexOf(item) === -1) { | |
list.push(item); | |
} | |
return list; | |
} | |
angular.forEach(item, function(i) { | |
if (list.indexOf(i) === -1) { | |
list.push(i); | |
} | |
}); | |
return list; | |
}; | |
angular.extend(angular, { | |
module: function(name, requires, configFn) { | |
if (!requires) { | |
return _module.call(angular, name, requires, configFn); | |
} | |
var autoLoad = []; | |
angular.forEach(requires, function(mod) { | |
try { | |
angular.module(mod); | |
} catch (e) { | |
if (!e.toString().match(/No module/)) { | |
throw e; | |
} | |
if (_loadMap[mod]) { | |
autoLoad = _appendAndFlatten(autoLoad, _loadMap[mod]); | |
} | |
} | |
}); | |
if (!autoLoad.length || (autoLoad.length === 1 && autoLoad[0] === "ng")) { | |
_inited = true; | |
return _module.call(angular, name, requires, configFn); | |
} | |
var module = _module.call(angular, name, [], configFn); | |
angular.forEach(module, function(val, key) { | |
if (!angular.isFunction(val)) { | |
return; | |
} | |
module[key] = function() { | |
_invokeQueue[name].push([key, Array.prototype.slice.call(arguments)]); | |
return module; | |
}; | |
_funcCache[key] = val; | |
}); | |
_invokeQueue[name] = []; | |
require(autoLoad, function() { | |
for (var n in _funcCache) { | |
module[n] = _funcCache[n]; | |
} | |
module.requires = requires; | |
if (angular.isFunction(configFn)) { | |
module.config(configFn); | |
} | |
for (var i = 0; i < _invokeQueue[name].length; i++) { | |
var call = _invokeQueue[name][i]; | |
module[call[0]].apply(module, call[1]); | |
} | |
_requests--; | |
if (_.businessTime) { | |
_.businessTime(); | |
} | |
}); | |
_requests++; | |
_inited = true; | |
return module; | |
}, | |
autoLoad: function(modules) { | |
angular.extend(_loadMap, modules); | |
}, | |
bootstrap: function() { | |
var args = Array.prototype.slice.call(arguments); | |
_.businessTime = function() { | |
if (_inited && _requests === 0) { | |
return _bootstrap.apply(angular, args); | |
} | |
}; | |
_.businessTime(); | |
} | |
}); | |
})(angular); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hmm. I think I see a serious roadblock -- anything written to use injected providers isn't going to work at runtime. That may be a deal killer...