2

I have been reading about AMD and implementations like requirejs. Most of the resources covers the usage and API's.

But, when it comes to implementing this, how can you load a JavaScript file into a variable just like that? For example, you can see functions like this:

define(['jquery'], function($){
});

var jquery = require('./jquery');

From an API consumer's perspective, all I can understand is that the file jquery.jshas magically become $, jQuery etc? How is that achieved?

Any examples would be helpful.

How do AMD loaders work under the hood? is a helpful read.

Edit: I think the eval answers below are nice because it actually is an eval problem in some ways. But I would like to know this from the perspective of an AMD specs implementation.

Nishant
  • 20,354
  • 18
  • 69
  • 101

4 Answers4

3

You don't load a javascript file into a variable, this is instead done by things such as browserify or webpack. Javascript itself can do this, but these modules generate a single file containing all your code. By calling require("file"), you are calling browserify's function to load a file named "file" stored in the code.

An example of this can be if you have a module

function demoModule(){
    console.log("It works!");
}
module.exports = demoModule

This makes module.exports now contain the "entire" contents of the file

Browserify/webpack puts that into a function that returns the module.exports of that file

function require(filename) {
    switch(filename){
        case "demofile":
            let module = {exports:{}}; ((module) => {
               function demoModule(){
                   console.log("It works!");
               }
               module.exports = demoModule
            })(module)
            return module.exports;
    }
};
    
require("demofile")();

Your file becomes a function that you can call with require("demofile") and it returns anything that was a module.export.

pfg
  • 2,348
  • 1
  • 16
  • 37
  • 1
    Performance is actually improved by having one big file instead of 20 files. Less HTTP requests make the page take less time to load while sacrificing lazy loading – pfg Oct 24 '17 at 18:30
  • So do you mean, some kind of compilation is involved to make this work? Also, if we make it a single file, how are things like lazy load going to be possible? It should be modular right? – Nishant Oct 24 '17 at 18:40
  • 1
    The modularity is in your code, but after compiling it it gets put into functions all in one big file. Compilation is necessary. It is good practice anyway to run your code through something like babel so old browsers can use new JS features. – pfg Oct 24 '17 at 18:43
2

You know how you can say eval(alert("hello!")) and it executes the code?

You can also:

var str = "hello!"
eval('alert("' + str + '");')

So the next step is to have a file that has your actual script in it:

var str = "hello"
alert(str)

then you can use a standard AJAX request to fetch that file into a variable, and you can eval() that variable.

Technically, eval() is considered evil - fraught with dangers - but there are other solutions (for example, injecting a script tag into the document body). I just went with eval() here to make the explanation easier.

theGleep
  • 1,179
  • 8
  • 14
  • `eval` is interesting. But I wanted to know if this can be done better. Even in the case of `eval`, you still have to read the file as a string. Is that possible? I have only seen `script` which is kind of a magic. – Nishant Oct 24 '17 at 18:14
  • Hmm...I guess I didn't understand what you were asking for, then. Hopefully some of the other answers here will clear up your questions. – theGleep Oct 24 '17 at 18:52
1

Extending what theGleep said.

Something like this:

var str = "if (x == 5) {console.log('z is 42'); z = 42;} else z = 0;";

console.log('z is ', eval(str));

For more read here.

But use eval() very cautiously and be absolutely sure about the pitfalls and drawbacks of eval().

Don't use it unless it is the only option.

Read this answer too.

Pritam Banerjee
  • 17,953
  • 10
  • 93
  • 108
0

The way define works under the hood is not by loading an "HTML Script into a variable". Typically a normal script can have multiple variables so it doesn't make sense to capture the value a variable! The eval approaches can probably do something like that if needed. It captures all that is there in the JavaScript source code.

The real key in AMD is that the define API maps a name to a function. Whenever you require with that name, it would just call that function and return the value to you. This return value is expected to be the module. This is a convention that makes everything work!

In other words, AMD uses an interesting convention (design pattern) to ensure that we get a modularization effect in JavaScript code. It is one level of indirection. Instead of the normal style of "write your code and get it executed in the global scope" paradigm, you just write a function that returns a single value that captures all the things you want to expose as a module to the consumer!

Nishant
  • 20,354
  • 18
  • 69
  • 101