JavaScript modules loading with eval() I recently asked to use eval() for a module function. Now I ended up doing a very weird function which does what I want. I like the idea I made it but I'm not so sure if this is state of the art, or more, good to build an application on.

index.html:

&lt;script src="module.js"&gt;&lt;/script&gt;

&lt;script&gt;

require('alert');

bam(); // 9
&lt;/script&gt;


module.js:

(function () {

    var require = window.require = function (fnName) {

        var dependencies = fnName.split(' '); // load multiple dependencies etc. (not nessecairy now)

        // REAL CASE WOULD BE, TO LOAD A .JS FILE INTO A STRING VAR
        var code = 'var bam = function() { var x = 1; var y = 2; var z = (x+y)*3; alert(z); }';

        return (function () {
            window.eval(code);
        })();
    }
})();


Is this a good solution for a require function like in PHP if I only load and eval() files made by me?
The functionality you are looking for is found in RequireJS and follows a spec called Asynchronous Module Definition (AMD). It is a mechanism that allows dependency management in JS, most notably in browsers.

As to why you think your own code is better, think again:


  it provides better latency on 3G network


It's because you think the modules are deployed "as is", as file-per-module basis. You are thinking of the "additional HTTP request per module" am I right? 

Sure, they work when broken down into modules. But you don't actually deploy them that way. You use the optimier which minifies your modules, and combines related modules into a file. This results in:


Smaller files due to minification
Lesser files due to dependency combination
Lesser files to download since your dependencies are grouped into related modules.


Also, the modules are cached once loaded. Once another modules requires a module that is already loaded by another module earlier in the execution of your code, it uses the cached one rather than requesting it again.


  I don't like unnecessary function wrappers... for every module, every require call. 


A require/define call is designed to:


define the dependencies
define the module
the filename is the module name


It isn't that hard to code:

//MyModule.js
define([
  'what',
  'you',
  'need'
],function(what,you,need){

  //what you do

  return whatYouWantExposedFromThisModule;

});



  I am now able to use my script like php's include.


Handling the modules

include is like appending one file to the other, which is synonymous to concatenating files. In JS, we don't want globals. What if one module of yours had a bam variable, but has bam in another and you required the two. How would you handle that?  Also, JS execution does not halt. How would you expect to do a require in your implementation? Synchronous XHR? preloading? That takes time! You'd be halting the execution for each require call of your implementation just to load a script.

&lt;script&gt;

  require('alert');
  //halt here to load alert? 
  //you'd block the UI, freeze the browser, lose the user
  bam(); // 9

&lt;/script&gt;


In the module definition in require, the code of the module lives in it's own scope. Nothing is spilled to the global scope. What is exposed by the module is only exposed to the function that requires it, which is also a closed scope. Also, modules are cached. Once a module is already loaded, future requires to that module are taken from the cache, not from the network. They are asynchronous, and does not block the UI thread and the requiring code only executes when the dependencies are loaded - nothing is halted while we wait for the dependencies to load.

Loading the modules

Suppose you will do AJAX with your eval approach - it's not cross-domain friendly, and cross-browser friendly (IE).

The concept of loading a module is based on script-loaders which can do cross-domain. It's similar to how JSONP works, but instead of an arbitrary callback, they are fed through define.

I suggest you read more about how script loaders and dependency loaders work. This is a broad topic and has it's own spec.