From 716c36a345e4883e88bda9cd8ec04975795b1847 Mon Sep 17 00:00:00 2001 From: Alexandr Zaytcev <13rentgen@gmail.com> Date: Thu, 8 May 2014 10:33:43 +0400 Subject: [PATCH 1/8] Add possibility to load external modules --- modules.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/modules.js b/modules.js index e4ae09b..254a515 100644 --- a/modules.js +++ b/modules.js @@ -173,7 +173,15 @@ var undef, while(require = requiresToProcess[i++]) { j = 0; dependOnDecls = []; applyCb = true; while(dep = require.modules[j++]) { - if(!isDefined(dep)) { + if(!isDefined(dep) && typeof curOptions.findDep === 'function' && typeof curOptions.loadModule === 'function' && curOptions.findDep(dep)) { + curOptions.loadModule(dep, function() { + pendingRequires = requiresToProcess; + nextTick(onNextTick); + }); + + applyCb = false; + break; + } else if (!isDefined(dep)) { onModuleNotFound(dep); applyCb = false; break; From e9e10bf9af8162f6ad350a982745fde5570f3830 Mon Sep 17 00:00:00 2001 From: Alexandr Zaytcev <13rentgen@gmail.com> Date: Thu, 8 May 2014 10:54:55 +0400 Subject: [PATCH 2/8] Fix code style --- modules.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules.js b/modules.js index 254a515..40d9086 100644 --- a/modules.js +++ b/modules.js @@ -181,7 +181,8 @@ var undef, applyCb = false; break; - } else if (!isDefined(dep)) { + } + else if(!isDefined(dep)) { onModuleNotFound(dep); applyCb = false; break; From f337f12deb1c98cf58fb6169c2242c043079e363 Mon Sep 17 00:00:00 2001 From: Alexandr Zaytcev <13rentgen@gmail.com> Date: Mon, 12 May 2014 12:41:58 +0400 Subject: [PATCH 3/8] Load external modules in 0.1.0 --- modules.js | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/modules.js b/modules.js index d074db8..45a8f53 100644 --- a/modules.js +++ b/modules.js @@ -152,7 +152,21 @@ var undef, while(i < len) { dep = deps[i++]; if(typeof dep === 'string') { - if(!modulesStorage[dep]) { + if(!modulesStorage[dep] && typeof curOptions.findDep === 'function' && typeof curOptions.loadModule === 'function' && curOptions.findDep(dep)) { + (function(dep, deps, cb) { + curOptions.loadModule(dep, function() { + pendingRequires.push({ + 'deps': deps, + 'cb': cb + }); + + nextTick(onNextTick); + }); + }(dep, deps, cb)); + + return; + } + else if(!modulesStorage[dep]) { cb(null, buildModuleNotFoundError(dep, fromDecl)); return; } From 826ed5b960b688e9e48879da2fbf867420e2d425 Mon Sep 17 00:00:00 2001 From: Alexandr Zaytcev <13rentgen@gmail.com> Date: Mon, 12 May 2014 13:41:19 +0400 Subject: [PATCH 4/8] Fix code style --- modules.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules.js b/modules.js index 45a8f53..cdd3dda 100644 --- a/modules.js +++ b/modules.js @@ -156,8 +156,8 @@ var undef, (function(dep, deps, cb) { curOptions.loadModule(dep, function() { pendingRequires.push({ - 'deps': deps, - 'cb': cb + deps : deps, + cb : cb }); nextTick(onNextTick); From 9021d823f3e91526e56ca9062a2cff3d046bcbab Mon Sep 17 00:00:00 2001 From: Alexandr Zaytcev <13rentgen@gmail.com> Date: Mon, 21 Jul 2014 21:02:00 +0400 Subject: [PATCH 5/8] Update README.md --- README.md | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/README.md b/README.md index cd6b707..1184506 100644 --- a/README.md +++ b/README.md @@ -79,3 +79,59 @@ modules.require( // module 'A' now resolved to a }); ```` + +####Дополнение к YModules#### + +В дополнение сделана возможность обработать возможность догрузки модуля по имени, если такого модуля в системе не зарегистированно + +````javascript +modules.setOptions({ + /** + * Функция поиска модуля + * + * @param {String} moduleName Имя модуля, который не зарегистирован в системе + * @return {Boolean} Можно ли этот модуль загрузить + */ + findDep: function( moduleName ) { + // body... + }, + /** + * Функция срабатывает, если функция findDep вернула true. + * + * @param {String} moduleName Имя модуля, который необходимо загрузить + * @param {Function} callback Функция обратного вызова, которую необходимо вызвать после загрузки модуля. + */ + loadModule: function( moduleName, callback ) { + // body... + } +}); +```` + +####Пример с загрузкой модуля#### + +Допустим, у нас есть внешняя утилита, которая умеет составлять объекты соотвествия имен модулей файлам в которых они находятся. В качестве загрузчка используется [LAB.js](http://labjs.com/). + +````javascript +var modulesDep = {"storage":"core.js", "menu": "ui.js"}; + +// Настраиваем поиск и загрузку незарегистрированных модулей +modules.setOptions({ + findDep: function( moduleName ) { + return modulesDep.hasOwnProperty(moduleName); + }, + loadModule: function( moduleName, callback ) { + var + filename = modulesDep[moduleName]; + // end of vars + + $LAB.script( getWithVersion(filename) ).wait(callback); + } +}); + + +modules.require( + ['storage'], + function( s ) { + // module 'storage' now resolved to 's' + }); +```` From c689c18933835535a4eb951cc4bde9ee0d10884b Mon Sep 17 00:00:00 2001 From: Alexandr Zaytcev <13rentgen@gmail.com> Date: Fri, 15 Aug 2014 18:58:03 +0400 Subject: [PATCH 6/8] Update tests --- modules/A.js | 37 +++++++++++++++++++++++++++++++++++++ modules/B.js | 39 +++++++++++++++++++++++++++++++++++++++ test/test.js | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 122 insertions(+) create mode 100644 modules/A.js create mode 100644 modules/B.js diff --git a/modules/A.js b/modules/A.js new file mode 100644 index 0000000..74fb22c --- /dev/null +++ b/modules/A.js @@ -0,0 +1,37 @@ +/** + * @param {Object} modules + */ +!function ( modules, undefined ) { + 'use strict'; + + var + /** + * @param {Function} provide Async module export + */ + module = function ( provide ) { + var + /** + * // moduleRealization description + */ + moduleRealization = function() { + return 100; + }; + // end of vars + + provide(moduleRealization); + }; + // end of vars + + + /** + * @module A + * @version 0.1 + */ + modules.define( + 'A', // Module name + [], // Dependies + module // Module realization + ); +}( + ( this.hasOwnProperty('modules') ) ? this.modules : modules +); \ No newline at end of file diff --git a/modules/B.js b/modules/B.js new file mode 100644 index 0000000..3520aaf --- /dev/null +++ b/modules/B.js @@ -0,0 +1,39 @@ +/** + * @param {Object} modules + */ +!function ( modules, undefined ) { + 'use strict'; + + var + /** + * @param {Function} provide Async module export + */ + module = function ( provide, A ) { + var + resultA = A(), + + /** + * // moduleRealization description + */ + moduleRealization = function() { + return 100 + resultA; + }; + // end of vars + + provide(moduleRealization); + }; + // end of vars + + + /** + * @module B + * @version 0.1 + */ + modules.define( + 'B', // Module name + ['A'], // Dependies + module // Module realization + ); +}( + ( this.hasOwnProperty('modules') ) ? this.modules : modules +); \ No newline at end of file diff --git a/test/test.js b/test/test.js index d7d573f..4690ae5 100644 --- a/test/test.js +++ b/test/test.js @@ -71,6 +71,52 @@ describe('resolving', function() { }); }); +describe('load modules', function() { + it('should properly load module and resolve dependencies', function(done) { + var + modulesDep = {'A': './modules/A.js', 'B': './modules/B.js'}; + + // Настраиваем поиск и загрузку незарегистрированных модулей + modules.setOptions({ + findDep: function( moduleName ) { + return modulesDep.hasOwnProperty(moduleName); + }, + loadModule: function( moduleName, callback ) { + var + fs = require('fs'), + vm = require('vm'), + filename = modulesDep[moduleName], + + // Proxy + originalRequire = require, + processProcess = process, + + context = vm.createContext({ + process: processProcess, + require: originalRequire, + modules: modules, + console: console, + exports: exports, + module: { + exports: exports + } + }), + + script = vm.createScript(fs.readFileSync(filename), filename); + + script.runInNewContext(context); + callback(); + } + }); + + modules.require(['B'], function(B) { + var res = B(); + res.should.have.been.equal(200); + done(); + }); + }); +}); + describe('errors', function() { it('should throw error on requiring undefined module', function(done) { modules.require(['A'], function() {}, function(e) { From 8d9916bde4e5f523a9ccea89beac9e509a7c3852 Mon Sep 17 00:00:00 2001 From: Alexandr Zaytcev <13rentgen@gmail.com> Date: Mon, 25 Aug 2014 01:45:05 +0400 Subject: [PATCH 7/8] Async load modules --- modules.js | 100 ++++++++++++++++++++++++++------------------------- modules/B.js | 11 +++--- modules/C.js | 37 +++++++++++++++++++ test/test.js | 52 ++++++++++++++++----------- 4 files changed, 126 insertions(+), 74 deletions(-) create mode 100644 modules/C.js diff --git a/modules.js b/modules.js index cdd3dda..1cda036 100644 --- a/modules.js +++ b/modules.js @@ -146,64 +146,68 @@ var undef, } var decls = [], - i = 0, len = unresolvedDepsCnt, - dep, decl; + unloadedDeps = [], + i = 0, j = 0, len = unresolvedDepsCnt, + dep, decl, + + require = function() { + while(i < len) { + dep = deps[i++]; + if(typeof dep === 'string') { + decl = modulesStorage[dep].decl; + } + else { + decl = dep; + } - while(i < len) { - dep = deps[i++]; - if(typeof dep === 'string') { - if(!modulesStorage[dep] && typeof curOptions.findDep === 'function' && typeof curOptions.loadModule === 'function' && curOptions.findDep(dep)) { - (function(dep, deps, cb) { - curOptions.loadModule(dep, function() { - pendingRequires.push({ - deps : deps, - cb : cb - }); - - nextTick(onNextTick); + if(decl.state === DECL_STATES.IN_RESOLVING && + curOptions.trackCircularDependencies && + isDependenceCircular(decl, path)) { + cb(null, buildCircularDependenceError(decl, path)); + return; + } + + decls.push(decl); + + startDeclResolving( + decl, + path, + function(_, error) { + if(error) { + cb(null, error); + return; + } + + if(!--unresolvedDepsCnt) { + var exports = [], + i = 0, decl; + while(decl = decls[i++]) { + exports.push(decl.exports); + } + cb(exports); + } }); - }(dep, deps, cb)); + } + }; - return; + while(j < len) { + dep = deps[j++]; + if(typeof dep === 'string') { + if(!modulesStorage[dep] && typeof curOptions.findDep === 'function' && typeof curOptions.loadModules === 'function' && curOptions.findDep(dep)) { + unloadedDeps.push(dep); } else if(!modulesStorage[dep]) { cb(null, buildModuleNotFoundError(dep, fromDecl)); return; } - - decl = modulesStorage[dep].decl; } - else { - decl = dep; - } - - if(decl.state === DECL_STATES.IN_RESOLVING && - curOptions.trackCircularDependencies && - isDependenceCircular(decl, path)) { - cb(null, buildCircularDependenceError(decl, path)); - return; - } - - decls.push(decl); - - startDeclResolving( - decl, - path, - function(_, error) { - if(error) { - cb(null, error); - return; - } + } - if(!--unresolvedDepsCnt) { - var exports = [], - i = 0, decl; - while(decl = decls[i++]) { - exports.push(decl.exports); - } - cb(exports); - } - }); + if(unloadedDeps.length) { + curOptions.loadModules(unloadedDeps, require); + } + else { + require(); } }, diff --git a/modules/B.js b/modules/B.js index 3520aaf..c31af7f 100644 --- a/modules/B.js +++ b/modules/B.js @@ -8,15 +8,16 @@ /** * @param {Function} provide Async module export */ - module = function ( provide, A ) { + module = function ( provide, A, C ) { var resultA = A(), + resultC = C(), /** * // moduleRealization description */ moduleRealization = function() { - return 100 + resultA; + return 100 + resultA + resultC; }; // end of vars @@ -30,9 +31,9 @@ * @version 0.1 */ modules.define( - 'B', // Module name - ['A'], // Dependies - module // Module realization + 'B', // Module name + ['A', 'C'], // Dependies + module // Module realization ); }( ( this.hasOwnProperty('modules') ) ? this.modules : modules diff --git a/modules/C.js b/modules/C.js new file mode 100644 index 0000000..d6a2705 --- /dev/null +++ b/modules/C.js @@ -0,0 +1,37 @@ +/** + * @param {Object} modules + */ +!function ( modules, undefined ) { + 'use strict'; + + var + /** + * @param {Function} provide Async module export + */ + module = function ( provide ) { + var + /** + * // moduleRealization description + */ + moduleRealization = function() { + return 200; + }; + // end of vars + + provide(moduleRealization); + }; + // end of vars + + + /** + * @module C + * @version 0.1 + */ + modules.define( + 'C', // Module name + [], // Dependies + module // Module realization + ); +}( + ( this.hasOwnProperty('modules') ) ? this.modules : modules +); \ No newline at end of file diff --git a/test/test.js b/test/test.js index 4690ae5..76ff093 100644 --- a/test/test.js +++ b/test/test.js @@ -74,44 +74,54 @@ describe('resolving', function() { describe('load modules', function() { it('should properly load module and resolve dependencies', function(done) { var - modulesDep = {'A': './modules/A.js', 'B': './modules/B.js'}; + modulesDep = {'A': './modules/A.js', 'B': './modules/B.js', 'C': './modules/C.js'}; // Настраиваем поиск и загрузку незарегистрированных модулей modules.setOptions({ findDep: function( moduleName ) { return modulesDep.hasOwnProperty(moduleName); }, - loadModule: function( moduleName, callback ) { + loadModules: function( modulesNames, callback ) { var - fs = require('fs'), - vm = require('vm'), - filename = modulesDep[moduleName], + fs = require('fs'), + vm = require('vm'), + loadedCnt = 0, // Proxy originalRequire = require, processProcess = process, - context = vm.createContext({ - process: processProcess, - require: originalRequire, - modules: modules, - console: console, - exports: exports, - module: { - exports: exports - } - }), - - script = vm.createScript(fs.readFileSync(filename), filename); - - script.runInNewContext(context); - callback(); + filename, file, context, script, i; + + for(i = 0; i < modulesNames.length; i++) { + filename = modulesDep[modulesNames[i]]; + (function(filename){ + file = fs.readFile(filename, 'utf8', function(err, data) { + context = vm.createContext({ + process: processProcess, + require: originalRequire, + modules: modules, + console: console, + exports: exports, + module: { + exports: exports + } + }); + script = vm.createScript(data, filename); + script.runInNewContext(context); + + loadedCnt++; + + if (loadedCnt === modulesNames.length) callback(); + }); + }(filename)) + }; } }); modules.require(['B'], function(B) { var res = B(); - res.should.have.been.equal(200); + res.should.have.been.equal(400); done(); }); }); From e559f5651163f8dcd8bb9d6a444bb664273bb87d Mon Sep 17 00:00:00 2001 From: Alexandr Zaytcev <13rentgen@gmail.com> Date: Wed, 27 Aug 2014 11:43:30 +0400 Subject: [PATCH 8/8] Update README.md --- README.md | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 1184506..841a58f 100644 --- a/README.md +++ b/README.md @@ -82,7 +82,7 @@ modules.require( ####Дополнение к YModules#### -В дополнение сделана возможность обработать возможность догрузки модуля по имени, если такого модуля в системе не зарегистированно +В дополнение сделана возможность обработать возможность догрузки модуля по имени, если такого модуля в системе не зарегистированно. В функцию loadModules будет передан массив имен модулей, которые необходимо загрузить. После того как все модули будут загружены, необходимо вызвать функцию обратного вызова. ````javascript modules.setOptions({ @@ -98,10 +98,10 @@ modules.setOptions({ /** * Функция срабатывает, если функция findDep вернула true. * - * @param {String} moduleName Имя модуля, который необходимо загрузить - * @param {Function} callback Функция обратного вызова, которую необходимо вызвать после загрузки модуля. + * @param {Array} moduleNames Массив имен модулей, которые необходимо загрузить + * @param {Function} callback Функция обратного вызова */ - loadModule: function( moduleName, callback ) { + loadModules: function( moduleName, callback ) { // body... } }); @@ -114,17 +114,37 @@ modules.setOptions({ ````javascript var modulesDep = {"storage":"core.js", "menu": "ui.js"}; +// Настройки LAB.js +$LAB.setGlobalDefaults({ + AllowDuplicates: false, + AlwaysPreserveOrder: true, + UseLocalXHR: false, + BasePath: '/javascripts/' +}); + // Настраиваем поиск и загрузку незарегистрированных модулей modules.setOptions({ findDep: function( moduleName ) { return modulesDep.hasOwnProperty(moduleName); }, - loadModule: function( moduleName, callback ) { + loadModules: function( modulesNames, callback ) { var - filename = modulesDep[moduleName]; + loadedCnt = 0, + filename, + i; // end of vars - $LAB.script( getWithVersion(filename) ).wait(callback); + for ( i = 0; i < modulesNames.length; i++ ) { + filename = modulesDep[modulesNames[i]]; + + (function(f) { + $LAB.script( getWithVersion(f) ).wait(function() { + loadedCnt++; + + if (loadedCnt === modulesNames.length) callback(); + }); + }(filename)); + } } });