jrburke/requirejs — Issue #183: Delay executing defines until first require
Author: fluidsonic
Created: 2012-02-13 21:10:13+00:00
State: open

Some good things about Advanced Module Loading are, that modules will be loaded asynchronously and on-demand.
On one side we split JavaScript code into separate modules to define and improve the project structure. On the other side it will only load these modules once they are actually needed, which leads to improved performance.

When r.js optimizes a project, it merges several modules into a single file and thus improves performance by reducing the number of files to load (less HTTP requests and so on).

r.js combines various modules into a single JavaScript file with multiple `define`s in it. But the downside is that require.js executes all of these `define`s directly (and thus "loads" these modules directly), even though no code actually `require`d them.

This leads to three problems:

* The application takes an unnecessary long time to load because lots modules which are still unused will be loaded at start-up time.
* The modules may be loaded in the wrong order. They will be loaded in the order the optimizer wrote the `define`s to the output and not in the order the application's `require` calls took place, which may be essential.
* The function passed to `define` may have side-effects, such as altering global variables or altering the DOM.

We had an issue with our CSS plugin, which creates one `define` during optimization for every CSS file imported. We expected the CSS to load when some code `require`s it and were suprised to see that all CSS was added to the DOM immediately on application start.

All of the problems listed above occurred here:

* All the CSS was loaded at once and slowed down the page directly after loading the optimized JavaScript file.
* The CSS did load in the order the optimizer wrote down the `define`s and not in the order the application requested the CSS files.
* This caused stylesheet rules to be evaluated in the wrong order, because the functions passed to `define` immediately added CSS to the DOM.

I suggest to run the function passed to `define` only when the module was actually requested by a call to `require`. The `define` function should really just define a module and should not execute it immediately.

Example:

```javascript
require(['css!a'], function() {
require(['css!b'], function() {
require(['css!c'], function() {
// ...
});
});
});
```

This code expects to load the following CSS files to load in order: a.css then b.css then c.css.
The optimizer may get the order right in simple cases, but as soon as either the order of `require` calls is runtime-dependend or the dependencies become more complex, the order will no longer be maintained.

If this explanation is not enough to describe the problem, I will try to create a simple test case for the issue.