I am currently writing a rather large client-side JS application which is made of of multiple modules, each in different files (before compiling). I am using Node.js to build the final script based on all the individual modules.
For the script to work properly all modules must be added in the proper order, so they can access any modules they depend on. One way to solve this is by maintaining an array of all the modules in the correct order to be inserted. I find that limiting though, having to add each file manually and in the correct position.
I have come up with a different solution to this, and would love to get some feedback on it.
First I have one wrapper file, which is wraped around all the modules. Looks like this:
(function( ns ){
var module = window[ns] = {
_modules: window[ns] && window[ns]._modules || {},
exports: function( name, mod ){
this._modules[name] = mod;
},
require: function( name ){
var mod = this._modules[name];
if(!mod) throw new Error(name + ' module not found');
return mod;
}
};
MODULES_INSERT
})( '_myCoolApp' );
Where it says "MODULES_INSERT" is where the modules get inserted.
Now inside the individual modules it looks something like this:
// export this module
module.exports('view', View);
function View(){ etc.. }
// import other module
var util = module.require('util');
And finally I have my build script (node.js) which adds all the modules/files, and orders them based on any module.requires they contain in their code, ensuring that all dependencies are loaded before they are required:
for(i in srcFiles){
file = srcFiles[i];
var content = fs.readFileSync(file.src);
content = '(function(){\n' + content;
content = content + '})();\n';
// find any module dependencies
var match, requires = [], regex = /module.require\(['"]([^'"]+)/g;
while(match = regex.exec(content)){
requires.push(match[1]);
}
file.requires = requires;
file.content = content;
}
for(i in srcFiles){
file = srcFiles[i];
recurse(file);
}
function recurse(file){
if(!file) return;
if(file.requires.length > 0) {
file.requires.forEach(function(req){
recurse(srcFiles[req]);
});
}
if(!file.added) results.push(file.content);
file.added = true;
}
code = results.join('');
code = wrapper.replace('MODULES_INSERT', code);
Is this solution way overkill? One downside I see to this, is what happens when two files require each other, which gets loaded first? Is there a more effective solution for this?