Difference Between data-main and normal script loading

When using RequireJS, what's the difference between including your script with

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

and

<script src="scripts/require.js"></script>

i.e. what does the data-main attribute change about loading in a script? I've read through the docs on this, and the different isn't entirely clear to me.

You will typically use a data-main script to set configuration options and then load the first application module. Note: the script tag require.js generates for your data-main module includes the async attribute. This means that you cannot assume that the load and execution of your data-main script will finish prior to other scripts referenced later in the same page.

The documentation mentions that you'll typically use a data-main script to set configuration options and load the first application module — but can't you also do that via a plain old script tag? Is there a benefit to doing configuration loading the application module with a data-main attribute?

Is the only different with data-main the asynchronous loading? Or is there something more?

Answers:

Answer

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.

Answer

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.

Answer

data-main is the script that require.js will process. As the documentation says, it is common to set configuration options in that script. But there are other ways to do that. In many cases it is the easiest and most effective place. But not always.

The script pointed to by data-main will also list the dependencies for the code that the file defines. The dependencies are where the meat is. It is typical, though not required, to have this first module load and execute what is ultimately the actual application.

Addendum in response to the comment:

There are some concepts you need to be aware of that will help make sense of this approach.

First is that there isn't a single (or a couple, or even a few) script(s). This type of loader is designed to handle lots and lots of very small scripts. Each with a very specific and often (preferably) single purpose. Call these scripts modules (or units).

Any given module might depend on any number of other modules in order to function. The AMD pattern allows the dependencies for each module to be listed within that module's definition.

RequireJS will sort out who needs what and in what order and not let scripts execute until all the modules they depend on are loaded and ready.

So this is not at all like putting a script link (or multiple links) in a page as we all grew up doing. It is a much different approach to javascript development. Once you get your head around it and figure out how to breakdown your code into discreet units of functionality it really is quite slick.

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

src will load "scripts/vendor/requirejs/require.js" first. Then data-main attribute will execute "scripts/main.js".

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.