Document entry point for a multi-module program
https://github.com/amdjs/amdjs-api/issues/8
How to define the top-level module of an application?
https://groups.google.com/group/amd-implement/browse_thread/thread/2fac555d3136b55b
> define(["some/module", "some/other/module", "some/other/sub/module"]);
Calling define() only with an array of dependencies looks interesting,
but it lacks the possibility to trigger a callback for the
availability of all modules.
> require.provides(["some/module", "some/other/module", "some/other/sub/module"]);
Beware that require is not defined at the top-level by AMD
specification, only as a local dependency.
Cheers,
Eric
Some requirejs specific notes below…
On Thu, Mar 1, 2012 at 1:02 PM, Taka Kojima <ta...@gigafied.com> wrote:
> I think RequireJS handles this by doing require.pause() at the top of files
> and require.resume() at the bottom of files, am I right James?
No, the pause/resume stuff was in some ancient code. Now any global
require()/requirejs() call triggers the module execution stuff.
James
The bigger problem is what Eric alludes to -- not having a compatible
API to kick off dependency resolution. I would rather see work put
into solving the larger problems first.
James
That only helps inform the loader what might show up in the file, it
does not tell the loader when to start executing factory functions.
There are some folks that do not want to execute the factory functions
until they are actually required by something, so they can seed a few
modules in a built file, but not take the overhead of running them
until they are needed. The execution chain needs to start somewhere,
usually with a global require()-like kickoff, which is likely at the
end of the file.
James
I don't remember objecting to that (maybe I did...just don't remember).
Anyhow, I don't object to that now: I also favor global require.
> Using anything on define() seems like the incorrect place, as I
> mentioned in that thread that Eric mentioned.
I agree that overloading define() is not the correct approach: to demand
several modules is not equivalent to defining a module.
fwiw, James' early API had one global function, namely require. He
augmented the API to differentiate between define and require as was
requested by many. I don't think trying stuff everything into define()
(now that we have it) makes sense given history.
> Some requirejs specific notes below�
You have a good point. One thing though: AMD promotes modular
development for JavaScript, each module being associated with an id in
a scope separated from the global namespace. But for two different
functions, AMD would take ownership of two different names in the
global namespace?
I feel like we should follow good practice here, and group both
require() and define() in a single global namespace, for example amd:
* amd.define()
* amd.require()
* ...
This would definitely avoid some confusion with separate
specifications for global require().
Cheers,
Eric
I think that is because we are still discovering the right execution
model, or that both should be allowed. RequireJS actually does a
hybrid approach: it collects the define calls, but waits for a
require() call to trigger the factory functions, and at that point
**all** define factory functions are called.
However, some users of almond, and some folks in requirejs land point
out that the execution of all define factories (in the order they are
registered) can be a different than the order used in dev, and some
things that do stuff like CSS work can be expensive to do all at once.
So I'm looking at changing it to only trace direct dependencies of a
require instead of all define() calls, for requirejs 1.1.
It would be curious to hear other implementers and their take on it.
If we agree on a model, then we can at least write it up as a standard
approach. It can be in a separate API doc, not the main AMD one if
that made more sense.
James
I would not be opposed to that as an option, but I do like at least
for define() to be available globally. If there needed to be some
disambiguation with another global define/require then allowing the
use of amd.define and amd.require seems fine.
I'm hoping there is not more new things to add for a top level API.
Since require() is used inside of define(), I think it is a concept
that carries over well to global usage, so I think we could get by
without mandating the use of amd.require and amd.define at the top
level. define() is already in wide usage as a global. But if this is a
big enough blocker for other implementers, who feel that
amd.require/amd.define should be available (at the very least,
amd.require() for the top level), I am open to changing requirejs to
allow for it.
But if it was just me, I would see how far I could go with just
keeping define and possibly using require as a global, instead of
creating a new 'amd' global.
James
FWIW, if we were to try to standardize something, I could see
standardizing the behavior you are using -- only execute factories on
a direct require/reference vs. when define() is called or executing
all defines at a certain time regardless of whether it was directly
asked for by a top level loader call.
I'm fine though waiting a bit on that, and seeing how it shakes out for people.
James
FWIW, if we were to try to standardize something, I could see
standardizing the behavior you are using -- only execute factories on
a direct require/reference vs. when define() is called or executing
all defines at a certain time regardless of whether it was directly
asked for by a top level loader call.
Wasn't this one of the main departures of AMD from CommonJS in the first place? Or between AMD and the present-day CommonJS Modules/2.0 or UncommonJS Modules specs?
http://tagneto.blogspot.com/2010/12/standards-and-proposals-for-javascript.html "AMD and Wrappings Differences"
What's changed?
This is slightly different than that. AMD should still execute all of
the direct dependencies for a given module.
What I want to change in requirejs: it currently runs *every* define
call in a built file, regardless on whether it was referenced as a
direct dependency. A direct dependency is one listed in the dependency
array or as a string literal require('') call (for simplified CJS
wrapping).
So for this module:
//main.js
define(['require', 'a', 'b'], function(require, a, b) {
return function (cb) {
require(['c'], cb);
});
});
If the built file contained the modules in this order: 'c', 'b', 'a',
'main', requirejs will execute c and b before a and main (assuming c
and b did not have dependencies) once a require()/requirejs() call
runs at the end of the file.
What I want to change: c's factory is not executed until it is
directly referenced, and that only factories that are explicitly
referenced as dependencies are executed, and in the order they are
referenced.
However, the 'a' and 'b' factories are still executed before executing
main's factory (the departure point for AMD and CJS). So, for the
initial file execution, the factory execution order would be:
* a
* b
* main
then at some time later, when main's exported function is called, c's
factory is run. If c also directly depended on 'd' (and a, b, main did
not), then d's factory function would then be executed before c's
factory.
James
Just for the sake of argument, assume we did this. The pseudo-module
"require" could also be renamed "amd". This means passing an object
instead of a function which allows for providing a prototypical
inheritance chain which is cheaper than copying properties to a closure.
Still, these seem to be fairly large changes at this point in AMD's life
cycle. I'm not at all convinced any of them are worth the chaos they
would cause.
--Rawld
On Fri, Mar 2, 2012 at 3:21 PM, Taka Kojima <ta...@gigafied.com> wrote:Is the method used in RequireJS any sort of standard or commonly-implemented-this-way type of deal? Is it something that would or could possibly be standardized in the AMD spec?I think that is because we are still discovering the right execution model, or that both should be allowed. RequireJS actually does a hybrid approach: it collects the define calls, but waits for a require() call to trigger the factory functions, and at that point **all** define factory functions are called.
require({
cache:{
"a":function(){
// all of the code that was in the resource that defined module "a"
},
"b":function(){
// all of the code that was in the resource that defined module "b"
},
"c":function(){
// all of the code that was in the resource that defined module "c"
}
}});
define("d", ["a", "b","c"], {something: true});
Yeah, I think it is just history. define() is already in the wild, it
is short too. Boilerplate is a real big turn-off, so the less the
better. Also, I think the hope was to be able to have a new require
API in CommonJS that would support the require needs in the browser.
Also, AMD did not get a real identity until later. I actually do not
like the name "AMD", too confusing with the chipset maker, I keep
reading the MD part as "mass destruction". :) But naming is hard, and
when talking about the initial API draft, I just used the name Kris
Zyp gave it, because naming is hard, and it was an API draft. But the
name seems to have stuck. The name of this list is not helping either.
:)
>> I'm hoping there is not more new things to add for a top level API.
>> Since require() is used inside of define(), I think it is a concept
>> that carries over well to global usage, so I think we could get by
>> without mandating the use of amd.require and amd.define at the top
>> level. define() is already in wide usage as a global. But if this is a
>> big enough blocker for other implementers, who feel that
>> amd.require/amd.define should be available (at the very least,
>> amd.require() for the top level), I am open to changing requirejs to
>> allow for it.
>>
>> But if it was just me, I would see how far I could go with just
>> keeping define and possibly using require as a global, instead of
>> creating a new 'amd' global.
>
> So if we have define and amd, we still have two global vars. I can see how
> taking ownership of "amd" in the global namespace should be less
> controversial than taking ownership of "require". So that seems reasonable.
>
> Just for the sake of argument, assume we did this. The pseudo-module
> "require" could also be renamed "amd". This means passing an object instead
> of a function which allows for providing a prototypical inheritance chain
> which is cheaper than copying properties to a closure.
That seems awkward to me. Maybe my eyes have just adjusted to using
"require" as the dependency name. I have thought of a use case that
may warrant a special dependency name "define", to allow defining
modules local to just that module, but it is really just a thought. I
prefer the shorter, functional API names, even though as you say the
prototype options are nice. Although, I can see problems if the
implementation does not allow var var req = amd.require; and it means
builders have more variations like that to parse out for static
analysis. Or it means mandating only using 'amd.require' in the files.
Yuck. The fact that require is used in define to me is enough to
namespace the require. "require" is already a special dependency name
anyway/already used in code, I say that boat has sailed.
So, I do not like the idea of a special "amd" dependency name, like
"require", "exports" and "module" are now.
> Still, these seem to be fairly large changes at this point in AMD's life
> cycle. I'm not at all convinced any of them are worth the chaos they would
> cause.
For me the only reason to consider an amd.require() is to get a
distinction from a Node/CommonJS "require" that might also be in scope
for some reason, and to overcome the objections that folks like John
Hann have about just using "require" in the global space.
Previously I had not really considered using "amd" for the object name
though, since I was not a fan of the actual name. And I think the hope
was that its APIs would just be a standard module loading API. No need
to group it under a namespace, it just "is".
If it gets us to a "common global entry point" API, then I'm open to
considering it further, but I do still favor just using require(). If
we go with "amd.require" at this point I would only want to spec out
"amd.require" and not an "amd.define" or anything else, and it should
only be a global, not a special dependency name.
But I would first want to get an idea on if "require" is just not
usable. I would like to see "make a require function available if
there is not already one there, and make sure your loader has a
loader-specific global API in case the developer really wants to call
your library in case of a require conflict. That global require is
only expected to support the API as specified for the local 'require'
spec. A loader may add other things, but they would be non-standard,
and not dependable for use as a top-level require call for loader
interop."
James
This is the approach I'm looking to convert to, except that all
define() calls are effectively like the require.cache calls, and only
a global require()/requirejs() call triggers the factory executions,
and only for modules that are directly referenced for that call's
dependency graph.
James
I was just kinda thinking out loud if we would've gone in a completely
different direction. But that's water under the bridge and I'm
definitely not proposing anything.
On the central point--should we define global require?--I'm with James.
I would vote yes on that. It seems like we could impl require to work as
an augmented CommonJS/node.js require. As always, I would favor a
has-bracketed impl that did not cost browser clients extra code. This
idea is on my list to look into.
> But I would first want to get an idea on if "require" is just not
> usable. I would like to see "make a require function available if
> there is not already one there, and make sure your loader has a
> loader-specific global API in case the developer really wants to call
> your library in case of a require conflict. That global require is
> only expected to support the API as specified for the local 'require'
> spec. A loader may add other things, but they would be non-standard,
> and not dependable for use as a top-level require call for loader
> interop."
>
Agree.
--Rawld
require
isn't actually a global but rather local to each module."