Last active
February 11, 2024 22:20
-
-
Save samba/6711258 to your computer and use it in GitHub Desktop.
Simplified AMD-style module framework
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
/* A lightweight module framework intended to provide (simplified) | |
* AMD-style module support. | |
* | |
* Currently its minified form yields 987 bytes, 577 after gzip compression. | |
* | |
* It DOES NOT parse module identifiers as paths (e.g. "/a/b" or "../a"). | |
* It assumes that all module IDs are simple strings, and seeks an exact | |
* match, without attempting to navigate any hierarchy. | |
* | |
* It DOES NOT parse incoming modules as string for require() statements. | |
* The require() method is completely synchronous; exceptions are thrown when | |
* modules are require()'d but don't exist. | |
* | |
* It DOES NOT support any kind of loading module. It assumes you'll load the | |
* scripts you need, when you need them. This framework's purpose is simply | |
* to ensure that modules are run only when their dependencies are registered. | |
* | |
* | |
* It DOES support AMD-style module definition, evaluating depend- | |
* encies with exact matching of module names, and running the module | |
* factories when all dependencies have registered. | |
* | |
* Without loading support, it's expected that components are concatenated | |
* via some sort of build script, or loaded independently in your site. It | |
* also effectively requires the use of module names given in their definition, | |
* as it doesn't relate filenames as module names. | |
* | |
* Suggested format: | |
* | |
* define('modname', [ 'dep1', 'dep2' ], function(dep1, dep2, exports){ | |
* | |
* exports.method = function(){...} | |
* | |
* // any return value here will be used instead of exports | |
* return exports | |
* | |
* }); | |
* | |
* | |
* See also: | |
* https://github.com/amdjs/amdjs-api/wiki/AMD | |
*/ | |
(function(global, undefined){ | |
var counter = 0; | |
var modules = {}; | |
var queue = []; | |
var RE_AUTO_MODULES = /^(require|exports|module)$/; | |
/* Find something in an array (like String.indexOf) */ | |
function _indexOf(elem){ | |
for(var i = 0; i < this.length; i++){ | |
if(this[i] === elem) return i; | |
} | |
return -1; | |
} | |
function require (name, callback){ | |
if(name in modules){ | |
return modules[ name ]; | |
} else | |
throw new Error('Unrecognized module: ' + name); | |
} | |
function resolve(name, factory, dependencies, cache){ | |
// Module-scope objects | |
var exports = {}, module = {}; | |
// Scoped names for each module (i.e. auto-populated) | |
var scope = {'exports': exports, 'module': module, 'require': require}; | |
var deps = [], i = dependencies && dependencies.length; | |
if(name in modules){ | |
throw new Error('Module already exists: ' + name); | |
} | |
while(i--){ // Resolve dependency sequence from cache | |
if(dependencies[i] in scope) | |
deps[i] = scope[ dependencies[i] ]; | |
else | |
deps[i] = cache[ dependencies[i] ]; | |
} | |
if(!dependencies) // Common-JS style (no dependencies declared) | |
deps = [ require, exports, module ]; | |
else | |
deps.push(exports, module); | |
// Evaulate the module's factory. | |
var resolved_name = name || counter++; | |
var result = factory.apply(cache, deps); | |
if(result === undefined) result = exports; | |
// Store the result | |
modules[ resolved_name ] = result; | |
// Notify waiting modules | |
setTimeout(function(){ | |
for(var i = 0; i < queue.length; i++){ | |
if(queue[i] && queue[i].call){ | |
queue[i].call(modules, resolved_name, result); | |
} | |
} | |
}, 1); | |
} | |
/* Prepare the cache and queue for a new module */ | |
function _module(name, dependencies, factory){ | |
var result; | |
var queue_index; | |
var cache = {}; // local stash of resolved dependencies | |
var i = dependencies && dependencies.length, | |
required = Number(i) || 0; | |
while(i--){ /* Collect existing dependencies */ | |
if(RE_AUTO_MODULES.test(dependencies[i])){ | |
required--; // these are automatically populated | |
} | |
else if(dependencies[ i ] in modules){ | |
cache[ dependencies[i] ] = modules[ dependencies[i] ]; | |
required--; | |
} | |
} | |
/* No remaining dependencies; resolve now */ | |
if(required === 0){ | |
return resolve(name, factory, dependencies, cache); | |
} | |
/* Queued method when waiting for dependencies */ | |
function resolver(depname, value){ | |
/* Ignore modules not required by this one */ | |
if(0 > _indexOf.call(dependencies, depname)){ | |
return false; | |
} | |
cache[ depname ] = value; | |
required--; | |
if(required === 0){ /* Resolve this module */ | |
resolve(name, factory, dependencies, cache); | |
queue[ queue_index ] = null; // de-queue | |
} | |
}; | |
resolver.module = name; // for debugging, really. | |
/* Enqueue this method for new module definitions. */ | |
return (queue_index = queue.push(resolver) -1); | |
} | |
function define(){ /* the public define() interface */ | |
var i = 0; // argument sentinel for flexible argument structures (as per AMD standard) | |
var args = arguments; | |
var id, deps, factory; | |
if(id = (typeof args[0] === 'string') && args[0]) i++; | |
if(deps = (args[i] && args[i].length && !args[i].call) && args[i]) i++; | |
if(factory = (args[i] && args[i].call) && args[i]) | |
_module(id, deps, factory); | |
} | |
/* Expose public methods */ | |
global['define'] = define; | |
global['require'] = require; | |
}(window, void 0)); | |
// vim: set nowrap tabstop=2 shiftwidth=2 softtabstop=0 expandtab textwidth=0 filetype=javascript foldmethod=indent foldcolumn=4 |
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
(function(q,t){function u(b){for(var a=0;a<this.length;a++)if(this[a]===b)return a;return-1}function p(b){if(b in k)return k[b];throw Error("Unrecognized module: "+b);}function r(b,a,c,e){var f={},h={},d={exports:f,module:h,require:p},g=[],m=c&&c.length;if(b in k)throw Error("Module already exists: "+b);for(;m--;)g[m]=c[m]in d?d[c[m]]:e[c[m]];c?g.push(f,h):g=[p,f,h];var s=b||v++,n=a.apply(e,g);n===t&&(n=f);k[s]=n;setTimeout(function(){for(var a=0;a<l.length;a++)l[a]&&l[a].call&&l[a].call(k,s,n)}, | |
1)}function w(b,a,c){function e(d,e){if(0>u.call(a,d))return!1;h[d]=e;g--;0===g&&(r(b,c,a,h),l[f]=null)}for(var f,h={},d=a&&a.length,g=Number(d)||0;d--;)x.test(a[d])?g--:a[d]in k&&(h[a[d]]=k[a[d]],g--);0===g?r(b,c,a,h):(e.a=b,f=l.push(e)-1)}var v=0,k={},l=[],x=/^(require|exports|module)$/;q.define=function(){var b=0,a=arguments,c,e,f;(c="string"===typeof a[0]&&a[0])&&b++;(e=a[b]&&a[b].length&&!a[b].call&&a[b])&&b++;(f=a[b]&&a[b].call&&a[b])&&w(c,e,f)};q.require=p})(window,void 0); | |
/* Statistics: {"compressedGzipSize": 577, "originalGzipSize": 2170, "compressedSize": 987, "originalSize": 5378, "compileTime": 0} */ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment