benjaminz
benjaminz

Reputation: 3228

Require JS: Detect data-main inside the script

In require js, is it possible to tell if a script is being loaded as data-main? For example, I have a script that can be used both as data-main or a module:

// script.js
if (this_is_data_main()) {
   console.log('do something main');
} else {
   console.log('do something else');
}

I can think of a hack by writing information as global variable, for example:

//index.html
<!doctype html>
...
<script> window.app.main = 'script'; </script>
<script data-main="script.js" src="require.js"></script>

Updated script.js:

// script.js
if (window.app && window.app.main === 'script') {
   console.log('do something main');
} else {
   console.log('do something else');
}

Upvotes: 1

Views: 293

Answers (1)

Louis
Louis

Reputation: 151441

Summary

RequireJS does not provide an "official" way of doing what you want. There's a unofficial way, which is brittle. However, I don't think you should be relying on detecting whether your script is loaded through data-main or not.

Long Explanation

RequireJS provides no direct means to do what you are trying to do. If you read the code of RequireJS you'll see that it reads data-main and ultimately appends it to the deps option of the current configuration. There is no other processing done besides a bit of path computation. (The path computation details are not important to the larger question you're asking here so I'm skipping these details.) By the time RequireJS is done with data-main, the code in your question is roughly equivalent to:

<script src="require.js"></script>
<script>
  require.config({
    deps: ["script"]
  });
</script>

You could inspect deps and see whether your module is in there. You'd find deps at this location require.s.contexts._.config.deps. The underscore is the name of the default context, by the way. But as you can probably tell by this bizarre location this is using a private API that could change with future releases of RequireJS. That's one problem. Another problem is that if require.config is called another time with a deps value, the first value of deps will be overwritten. So this would fail depending on circumstances. Too brittle for my taste.


Ultimately I would not rely on having module behavior depend on whether the module was loaded by being listed in data-main rather than some other way. I've shown above an equivalent to using data-main. Here's another one:

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

And I could list a bunch of other variations. The point is that from a module loading standpoint data-main is a convenience. It should not be given more significance than being a convenience. I've used data-main and the two alternatives shown above in various contexts. The context will usually determine which options are possible or desirable. For instance I've answered questions on SO where the OP was running in a context where RequireJS was already loaded by the time their own code would run. So they just would not have been even able to rely on data-main. (This can happen, for instance, for components that serve as plug-ins in a larger framework: the framework uses RequireJS so it makes RequireJS available to plugins, but the plugins are limited to adding script elements.)

Another issue with relying on data-main is that this is a RequireJS thing. It is possible to load AMD modules with other tools like SystemJS or bundle AMD modules using other tools like Webpack. If your code depends on data-main it won't work properly when working with those other tools.


You could have your main module export an initialization function that takes options and configures your module as the user needs it.

If you want something that kicks in immediately upon module loading and not have to call any functions, one way to do it without polluting the global JavaScript space would be to have your module look for a well-known script element (which a specific id or a specific class) that has a type application/json. Since it is JSON, it is not executed by the browser but it is accessible to scripts that need it. It would contain a JSON object that your module reads for configuration. This question deals with how to get the JSON out of the script.

Upvotes: 1

Related Questions