Permalink
Browse files

Handle Asynchronous Module Definition modules and default to using th…

…at as the output
  • Loading branch information...
1 parent 43bf368 commit 72d41e68ef57e5853358ffe3e68e2e7eba8fc5ae @kriszyp committed Sep 17, 2010
Showing with 113 additions and 53 deletions.
  1. +61 −19 lib/jsgi/transporter.js
  2. +52 −34 lib/receiver.js
View
@@ -1,5 +1,10 @@
//TODO: optionally write to target file
-exports.Transporter = function(options, app) {
+
+require.def||(require.def=function(factory){module.exports=factory(require);});
+require.def(function(require){
+var exports = Transporter;
+exports.Transporter = Transporter;
+function Transporter(options, app) {
var options = options || {},
prefix = options.urlPrefix || "/lib/",
resolveDeps = "resolveDeps" in options ? options.resolveDeps : true,
@@ -80,7 +85,7 @@ exports.Transporter = function(options, app) {
}
errors.forEach(write);
if(isPaused){
- write("require.resume();\n");
+ write("require.resume && require.resume();\n");
}
if(requestedModules.length > 1){
write('require.def("' + requestedModules.join(",") + '", [], function(){});');
@@ -106,7 +111,7 @@ exports.Transporter = function(options, app) {
if(modules[moduleName]){
if(modules[moduleName] === 1 && !isPaused && write && !converter.start){
// we need to pause to get all the dependencies loaded
- write("require.pause();\n");
+ write("require.pause && require.pause();\n");
isPaused = true;
}
return true;
@@ -138,9 +143,7 @@ exports.Transporter = function(options, app) {
write(fileContents);
return true;
}
- if(excluded[moduleName] || fileContents.indexOf("require.def(") > -1){
- // also hand-coded modules that define their require.def's don't need wrapping/resolution,
- // they can be directly written
+ if(excluded[moduleName]){
write(fileContents);
return true;
}
@@ -155,7 +158,7 @@ var depNames = {};
var fulfilledDeps = {};
var deps = [];
// CommonJS module wrapper
-exports.CommonJS = function(moduleName, fileContents, loadModule, modules, write){
+exports.CommonJSTransportD = function(moduleName, fileContents, loadModule, modules, write){
fulfilledDeps[moduleName] = true;
var baseModule = moduleName.substring(0, moduleName.lastIndexOf("/") + 1);
fileContents.replace(/require\s*\(\s*['"]([^'"]*)['"]\s*\)/g, function(t, moduleId){
@@ -201,27 +204,58 @@ exports.CommonJS = function(moduleName, fileContents, loadModule, modules, write
}
};
var first;
-exports.CommonJS.start = function(write){
+exports.CommonJSTransportD.start = function(write){
first = true;
fulfilledDeps = {};
deps = [];
depNames = {};
write('require.define({\n');
first = true;
};
-exports.CommonJS.end = function(write){
+exports.CommonJSTransportD.end = function(write){
write('\n},[')
deps = deps.filter(function(dep){
return !fulfilledDeps[dep];
});
write((deps.length ? '"' + deps.join('", "') + '"' : '') + ']);');
};
// CommonJS module wrapper
-exports.CommonJSTransportC = function(moduleName, fileContents, loadModule, modules, write){
+exports.CommonJS = function(moduleName, fileContents, loadModule, modules, write){
var deps = [];
var depNames = {};
var baseModule = moduleName.substring(0, moduleName.lastIndexOf("/") + 1);
- fileContents.replace(/require\s*\(\s*['"]([^'"]*)['"]\s*\)/g, function(t, moduleId){
+ var needsStaticAnalysis = true;
+ var firstRequireDef = fileContents.indexOf("require.def(");
+ if(firstRequireDef > -1){
+ // in AMD form
+ fileContents = fileContents.replace(/require\.def\(\s*(?:['"]([^'"]*)['"]\s*,)?\s*(?:(\[[^\]]*\]\s*),)?/,function(t, id, depsJson){
+ if(depsJson){
+ JSON.parse(depsJson).forEach(onDependency);
+ }else if(!id){
+ // anonymous, no deps, should use static analysis
+ staticAnalysis();
+ }
+ deps = deps.filter(function(dep){
+ return !fulfilledDeps[dep];
+ });
+ // TODO: Once there is a good support for optional dependencies, hopefully we can check the deps.length and omit the deps if there are none
+ if(!depsJson && !id){// && deps.length){
+ deps = ["require", "exports", "module"].concat(deps);
+ }
+ return 'require.def("' + moduleName + '",' + (deps.length ? '["' + deps.join('", "') + '"],' : '');
+ });
+ }else{
+ staticAnalysis();
+ deps = deps.filter(function(dep){
+ return !fulfilledDeps[dep];
+ });
+ }
+ function staticAnalysis(){
+ fileContents.replace(/require\s*\(\s*['"]([^'"]*)['"]\s*\)/g, function(t, moduleId){
+ onDependency(moduleId);
+ });
+ }
+ function onDependency(moduleId){
// handle relative references
if(moduleId.charAt(0) == "."){
if(moduleId.charAt(1) == "."){
@@ -250,15 +284,21 @@ exports.CommonJSTransportC = function(moduleName, fileContents, loadModule, modu
if(!loadModule(moduleId, write)){
deps.splice(deps.indexOf(moduleId), 1);
}
- });
+ }
if(write){
- write('require.define("');
- write(moduleName);
- write('", ["require", "exports", "module"');
- write((deps.length ? ', "' + deps.join('", "') + '"' : '') + '], ');
- write('function(require, exports, module) {');
- write(fileContents);
- write('\n});\n');
+ if(firstRequireDef == -1){
+ write('require.def("');
+ write(moduleName);
+ write('", ["require", "exports", "module"');
+ write((deps.length ? ', "' + deps.join('", "') + '"' : '') + '], ');
+ write('function(require, exports, module) {');
+ write(fileContents);
+ write('\n});\n');
+ }else{
+ // already in AMD form
+ write(fileContents);
+ write('\n');
+ }
}
};
@@ -310,3 +350,5 @@ exports.DojoRequireJS = function(moduleName, fileContents, loadModule, modules,
write('\n});\n');
}
};
+return exports;
+});
View
@@ -1,48 +1,66 @@
-/** A very lightweight implementation of transport/D's require.define and
+/** A very lightweight implementation of CommonJS Asynchronous Module Definition
+ * (require.def) and
* require.ensure. This can only receive modules, it will not proactively attempt to load
- * any modules, so you must not turn off the default transporter setting of
- * resolveDeps to use this module receiver.
+ * any modules, so you must leave the default transporter setting of
+ * resolveDeps on (true) to use this module receiver.
*/
(function(){
var factories = {},
modules = {};
- function makeRequire(currentId){
- return function(id){
- if(id.charAt(0) === '.'){
- id = currentId.substring(0, currentId.lastIndexOf('/') + 1) + id;
- while(lastId !== id){
- var lastId = id;
- id = id.replace(/\/[^\/]*\/\.\.\//,'/');
- }
- id = id.replace(/\/\.\//g,'/');
- }
- var module = modules[id];
- if(module){
- return module;
- }
- if(!factories[id]){
- throw new Error("Module " + id + " not found");
- }
- var module = factories[id](makeRequire(id), modules[id] = {}, {});
- if(module){
- return modules[id] = module;
+ function req(id){
+ var module = modules[id];
+ if(module){
+ return module;
+ }
+ if(!factories[id]){
+ throw new Error("Module " + id + " not found");
+ }
+ var factory = factories[id];
+ var args = factory.deps || (factory.length ? ["require", "exports", "module"] : []);
+ var exports = modules[id] = {};
+ for(var i = 0; i < args.length; i++){
+ var arg = args[i];
+ switch(arg){
+ case "require": arg = function(relativeId){
+ if(relativeId.charAt(0) === '.'){
+ relativeId = id.substring(0, id.lastIndexOf('/') + 1) + relativeId;
+ while(lastId !== relativeId){
+ var lastId = relativeId;
+ relativeId = relativeId.replace(/\/[^\/]*\/\.\.\//,'/');
+ }
+ relativeId = relativeId.replace(/\/\.\//g,'/');
+ }
+ return req(relativeId);
+ }; break;
+ case "exports": arg = exports; break;
+ case "module": var module = arg = {exports: exports}; break;
+ default: arg = req(arg);
}
- return modules[id];
- };
+ args[i] = arg;
+ }
+
+ exports = factory.apply(this, args);
+ if(module && module.exports != modules[id]){
+ exports = module.exports;
+ }
+ if(exports){
+ return modules[id] = exports;
+ }
+ return modules[id];
}
require = {
- define: function(modules){
- for(var i in modules){
- factories[i] = modules[i];
- if(typeof factories[i] != "function"){
- throw new Error("Module " + id + " must be defined as a function");
- }
+ def: function(id, deps, factory){
+ if(typeof deps == "function"){
+ factories[id] = deps;
+ }else{
+ (factories[id] = factory).deps = deps;
}
},
ensure: function(modules, callback){
- var require = makeRequire("");
- modules.forEach(require);
- callback(require);
+ for(var i = 0; i < modules.length; i++){
+ req(modules[i]);
+ }
+ callback(req);
}
};
})();

0 comments on commit 72d41e6

Please sign in to comment.