Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

With AMD modules, when (or why) is it OK to use require() within define()?

My understanding of AMD modules (using for example RequireJs or curl.js) is:

require() is used to asynchronously load different modules and when loaded then the callback fn is executed.

And to define a module, you would have separate scripts that use define()

But I've seen some modules use require() inside their function definition, e.g.

define([a, b, c], function(i, ii, iii){ 
    require([d, e, f], function(d, e, f) {
        // do some stuff with these require()'d dependancies
    })
    /* rest of the code for this module */ 
}) 

But I find this confusing because I would have thought that if a module has dependancies then they should be passed through via the main define([dependancies], fnDefinition) function and not within it via require() as per the above example is doing.

Is there a reasoning behind this?

like image 672
Integralist Avatar asked Oct 20 '11 11:10

Integralist


People also ask

What is AMD?

Why AMD? This page talks about the design forces and use of the Asynchronous Module Definition (AMD) API for JavaScript modules, the module API supported by RequireJS. There is a different page that talks about general approach to modules on the web. What are JavaScript modules? What is their purpose?

Why is AMD so popular for modules?

Seeing a function wrapped around functionality is a very common sight and does not add to the reading cost of a module. AMD modules require less tooling, there are fewer edge case issues, and better debugging support. What is important: being able to actually share code with others. AMD is the lowest energy pathway to that goal.

Where did the AMD format come from?

The AMD format comes from wanting a module format that was better than today's "write a bunch of script tags with implicit dependencies that you have to manually order" and something that was easy to use directly in the browser. Something with good debugging characteristics that did not require server-specific tooling to get started.

Can I use CommonJS with AMD?

The CommonJS modules that would not work in an AMD wrapper will also not work as a Harmony module. AMD's code execution behavior is more future compatible. One of the criticisms of AMD, at least compared to CJS modules, is that it requires a level of indent and a function wrapping.


1 Answers

There are a few reasons you may want to use require() in a module.

But first, be sure you request a reference to the correct require variable. In your example, the reference to require is a global. You want a reference to a require that is scoped to the context of your module (sometimes called a "local require"). This is easy:

define(["a", "b", "c", "require"], function(i, ii, iii, require){ 
    require(["d", "e", "f"], function(moduleD, moduleE, moduleF) {
        // do some stuff with these require()'d dependencies
    })
    /* rest of the code for this module */ 
}); 

The main reason this is important is to ensure that relative module ids (e.g. "./peerModule" or "../unclePath/cousinModule") are resolved correctly. (This is one of the reasons, curl.js doesn't have a global require by default.)


Reasons to use a local require:

  1. you don't know which modules are needed at build time (or at load time) due to run-time conditions
  2. you explicitly want to defer loading of some modules until they're needed
  3. you want to load a variation of a module based on results of feature detection (although something like dojo's "has!" plugin might be a better solution ( sorry, link eluding me))

Lastly, AMD defines a second usage of require for compatibility with modules authored in the CommonJS Modules/1.1 which are then wrapped in a define. These look like this:

define(function(require, exports, module){ 
    var a = require("pkgZ/moduleA"), // dependency
        b = require("pkgZ/moduleB"); // dependency
    /* rest of the code for this module */ 
}); 

Server-side javascript devs may find this format appealing. :)

Some AMD loaders (such as RequireJS 0.2+, dojo 1.7+, bdLoad, and curl.js 0.6+) will detect this hybrid AMD/CJSM1.1 format and find dependencies by scanning the module for require calls.

like image 174
unscriptable Avatar answered Oct 02 '22 15:10

unscriptable