Difference Between data-main and normal script loading

data-main is just another way to perform the initial require call of your application. To illustrate... this:

<script data-main="scripts/main" src="scripts/require.js"></script>

is equivalent to this:

<script src="scripts/require.js"></script>
<script>require(["scripts/main"])</script>

The two forms are both asynchronous. This is really all there is to it. Considerations about how many entry points you have or where the RequireJS configuration is going to be located are completely orthogonal to the use of data-main. To put it differently, these considerations play a role in your use of data-main to the exact same extent that they play a role in your use of require(["scripts/main"]).

The part of the documentation you quoted is just obscuring things by mentioning that the script loaded with data-main creates a script element in the head element with the async attribute set, because this is not different from loading any script through RequireJS. Every single script loaded by RequireJS will have a script element created for it, in the head, and have the async attribute set.

It is common to use data-main for applications that have only a single entry point, and to put RequireJS' configuration in the module specified in data-main, but it is not required by any means. For instance, this is a perfectly valid use:

<script>
    require = {
        // RequireJS config here...
    };
</script>
<script data-main="scripts/main" src="scripts/require.js"></script>
<script>
    require(["foo"], function (foo) {
        foo.something();
    });
</script>

The configuration is given to RequireJS by setting require in the global space before loading RequireJS. (If require is defined before RequireJS is loaded, it will take require's value as its configuration.) Besides kicking off the application by loading scripts/main, this code also loads foo and calls a method on it: two entry points.


data-main is for when you want to have a single entry point to your application. That single script line will load RequireJS along with scripts/main.js and kick off your app.

The result of

<script data-main="scripts/main" src="scripts/require.js"></script>

is that <script async src="scripts/main.js"></script> is appended to the document at runtime; this is the script that will contain your require.config() block and pull in your first application script. If you don't specify a data-main, then you're only loading Require and none of your app scripts, unless you explicitly load a config file and the first module.

What do you think Require will load if you don't tell it to load anything?


If you do not use data-main, you must provide an entry point after loading Require (this is how I have always done it, for no good reason other than that's how I learned it.) Read about the configuration options to see how you would do this.

I use this pattern in development:

<script src="js/lib/require.js"></script>
<script src="js/config.js"></script>
<script>
  // same as data-main
  require.config({baseUrl : 'js'});
  require(['js/main']);
</script>

As a single entry point, the contents of config.js and the subsequent require(['js/main']) call would be in whichever script is referenced as data-main.


If you use the static optimizer to build a production bundle, none of this matters because you just load the bundle.