amdjs / amdjs-api

Houses the Asynchronous Module Definition API
https://groups.google.com/group/amd-implement
4.31k stars 499 forks source link

Specifying configuration options #20

Open jugglinmike opened 10 years ago

jugglinmike commented 10 years ago

The "commonConfig" document defines a set of configuration options that AMD script loaders should support. It does not specify how these options can actually be specified.

The AMD specification is incomplete without this detail. Consumers are forced to find and use a custom, non-standard API in order to specify standardized information. This makes application code less portable generally.

As a strawman proposal, consider a new config method defined on the global define function. Example usage:

define.config({
  baseUrl: './foo/bar'
});
jrburke commented 10 years ago

We talked a bit in IRC about this, IIRC, and I am open to specifying some specifics about this, but I do believe this is a loader API responsibility, and not something that should be on define(), as define() is for module definitions that should be valid outside any config values.

This will be true in ES6 too, where the config options will be on ModuleLoader, and not in any module definition syntax or API. Although I would prefer to see a ModuleLoader.prototype.config() to accept the API, and have given feedback to that effect to the ES folks.

For AMD though, I would be open to specifying that it should be loader.config({}), where "loader" is the loader-specific API (requirejs.config(), curl.config(), inject.config()). If the loader supports a global require() function, then require.config() could be expected to be found, but it would not mandatory, just if the loader decided to provide a global require().

Would like to hear from some other AMD folks on that though before writing in the API doc. But I definitely think it should not be on define().

jugglinmike commented 10 years ago

The part of our previous conversation that I didn't follow was the distinction between the module loading and module definition API. It's true that the define function defines modules, but it is also capable of loading modules. This means that the configuration isn't only a concern of the loader function.

This may just be that I am not familiar enough with ES6 module loaders. As I understand them, their responsibility is much more directed than AMD's define: they only import and do not export. This understanding is what leads me to believe that relegating loader configuration to the loader API makes more sense for ES6 than for AMD.

jrburke commented 10 years ago

Perhaps this will help:

define on its own does not actually trigger any module loading. If a script has a bunch of defines in it, no top level require([]) calls, and that is loaded by a script tag, no actual loading happens, the define() arguments are just kept in a storage facility in the loader. Only once there is a top level require([]) call should the define() calls be traced, and only for the modules that are needed as part of that dependency tree.

So to get module loading to occur, the loader API, via require([]), is needed to trigger any module loading.

In requirejs, require.config({ context: 'something'}) is like new ModuleLoader({}) in ES module syntax, with System being the default loader that is instantiated by default, similar to the '_' default context used in requirejs, for any top level require([]) calls.

In ES, the configuration of how loading is done is done on a ModuleLoader instance (or System, if configuring the default loader). Similarly, I view config working in AMD module loaders, off the module loader API. For loaders like requirejs that allow using require as the default loader, require.config() makes sense. Or, requirejs.config if wanting to use the loader implementation's name.