Skip to content

Instantly share code, notes, and snippets.

@regular
Created November 10, 2010 23:47
Show Gist options
  • Save regular/671736 to your computer and use it in GitHub Desktop.
Save regular/671736 to your computer and use it in GitHub Desktop.
an implementation of require() that runs in a browser and downloads code from a server
// require.js
// a browser-side implementation of require()
// (c) 2010 Jan Bölsche <[email protected]>
// See my blog post at http://blog.lagomorph.de/2010/11/require-requirements
// This code is licenced under the terms of the GPL (any version you prefer)
// requires JQuery.
var moduleExports = {}; // hash of hashes, stores exported objects of all loaded modules
// loadModule() loads a module from the web server and resolve all
// requirements (by loading more code from the server)
// The exported objects of all loaded modules can be found
// in moduleExports.
// This function returns immediately and has no return value.
// If the operation succeeds, onLoad is called with the name of the
// module that was just loaded as the first argument and its exports
// as the second argument. onError is called with the name of the module
// in case the file could not be downloaded.
// CAVEATS
// TODO: catch and report errors that occur while evaluating a module's code.
// FIXME: modules may be loaded and evaluated more then once.
function loadModule(moduleName, onLoad, onError) {
// evaluateModule() runs downloaded code and
// potentially triggers the download of its dependencies.
// It only succeeds if all dependencies are already loaded.
// Otherwise it will call loadModule which in turn will
// call back evaluateModule() once the new code is loaded.
function evaluateModule(moduleName, code, onSuccess, onError) {
exports = {}; // will be filled by the module to be evaluated
// The following is the implementation of require()
// that is visible to downloaded modules
// while they are being evaluated.
// If the path specified refers to a module
// that was already loaded, the method succeeds.
// Otherwise it triggers the download and fails with
// an exception.
// Once the download is finished, the callback function
// retries to evaluate the module that originally called
// require().
var require = function(path) {
if (path.substring(0, 2) == "./") {
path = path.substring(2);
}
if (path in moduleExports) {
console.log("required module " + path + " is already loaded.");
return moduleExports[path];
}
console.log("required module " + path + " is not loaded yet.");
loadModule(path, function() {
evaluateModule(moduleName, code, onSuccess, onError);
}, onError
);
throw "required module " + path + " not yet loaded (now laoding)";
}
// the following line might throw an
// excpetion due to an unresolved required module
// in that case we will be called again after
// that module has been loaded, so we just return.
eval(code);
// otherwise we get here, store the exports
// exposed by the new module for future use
// and report success.
moduleExports[moduleName] = exports;
onSuccess();
return exports;
}
if (moduleName in moduleExports) {
if (onSuccess != undefined) {
onSuccess(moduleName, moduleExports[moduleName]);
}
return;
}
console.log("trying to load module " + moduleName + " ...");
jQuery.ajax({
dataType: 'text',
url: '/' + moduleName.toLowerCase() + '.js',
'success': function(data, textStatus, request) {
evaluateModule(moduleName, data,
function() {
if (onLoad != undefined) {
onLoad(moduleName, moduleExports[moduleName]);
}
},
function() {
if (onError != undefined) {
onError(moduleName);
}
}
);
},
'error': function(request, textStatus, errorThrown) {
console.log("failed to download module " + moduleName);
if (onError != undefined) {
onError(moduleName);
}
}
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment