I wanted to start a thread about standardizing built modules format, I'm proposing a solution, but would also like to hear about how other AMD loaders handle built files.
I am thinking that a top-of-file define call, that looks like this, should work pretty well:
The idea being that if you only specify an array and no other arguments, you are saying "This file provides definitions for all of the modules in this array".
The only issue with the above format is that it breaks use cases of anonymous modules which are arrays that have no dependencies.
The nice thing about this, is that it also allows you to specify multiple named modules per file during the dev process (don't know if this is a common use case, but it's a nice side effect).
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?
How do other AMD loaders handle built files?
I know we could handle this by essentially calling something like require.pause() at every define call, and require.resume() on the script load events, but that negatively impacts the speed of all other modules that only have one define() call per file.
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.
As Eric mentioned, we've talked a bit on this before. I favor just using a global require, but the folks that prefer not to use that, IIRC, John Hann and Rawld, I do not think have proposed something else. Using anything on define() seems like the incorrect place, as I mentioned in that thread that Eric mentioned.
Some requirejs specific notes below…
On Thu, Mar 1, 2012 at 1:02 PM, Taka Kojima <t...@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.
In this scenario, we essentially have to halt all dependency lookup until the final define() call is made. This is somewhat unflexible and leads to lesser speed overall (although in most cases, it will be negligible). It also stops me from doing any sort of async define call in the script.
If we replaced the define call for "c" with the following:
RequireJS would try to look elsewhere for "c", even though it is defined later on in the file, just not immediately.
d depends on a, b and c, which are defined later in the file, so how else do we solve this? Using existing functionality it could be something like this:
I don't even know if the above will currently work in RequireJS, but the gist of it is that at the top of every file we say "this file provides definitions for these modules".
It is more code and I was suggesting that we could simplify it into a a single function call with an array like:
define(["d", "a", "b", "c"]);
Doing something like the above allows us to not halt dependency lookup/fetching at any point the script's execution, and also allows for async calls to define().
This only applies to files with more than one named module definition in them, so in most scenarios these are files outputted by a build/optimization tool.
This may be viewed as "going backwards", i.e. AMD loaders already work with multiple named define() calls in them (that depend on each other), without any extra code, but I believe this approach definitely has some pros to it.
On Fri, Mar 2, 2012 at 11:31 AM, James Burke <jrbu...@gmail.com> wrote: > As Eric mentioned, we've talked a bit on this before. I favor just > using a global require, but the folks that prefer not to use that, > IIRC, John Hann and Rawld, I do not think have proposed something > else. Using anything on define() seems like the incorrect place, as I > mentioned in that thread that Eric mentioned.
> Some requirejs specific notes below…
> On Thu, Mar 1, 2012 at 1:02 PM, Taka Kojima <t...@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.
The very minor possible speed gain (which is dwarfed by any network activity) is not worth the extra complication of expanding the API and the burden on implementers to match. This has not come up as an issue in real world scenarios.
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.
On Fri, Mar 2, 2012 at 11:55 AM, Taka Kojima <t...@gigafied.com> wrote: > There is some overflow into those other discussions, but I was more talking > about this scenario:
> In this scenario, we essentially have to halt all dependency lookup until > the final define() call is made. This is somewhat unflexible and leads to > lesser speed overall (although in most cases, it will be negligible). It > also stops me from doing any sort of async define call in the script.
> If we replaced the define call for "c" with the following:
> RequireJS would try to look elsewhere for "c", even though it is defined > later on in the file, just not immediately.
> d depends on a, b and c, which are defined later in the file, so how else do > we solve this? Using existing functionality it could be something like this:
> I don't even know if the above will currently work in RequireJS, but the > gist of it is that at the top of every file we say "this file provides > definitions for these modules".
> It is more code and I was suggesting that we could simplify it into a a > single function call with an array like:
> define(["d", "a", "b", "c"]);
> Doing something like the above allows us to not halt dependency > lookup/fetching at any point the script's execution, and also allows for > async calls to define().
> This only applies to files with more than one named module definition in > them, so in most scenarios these are files outputted by a build/optimization > tool.
> This may be viewed as "going backwards", i.e. AMD loaders already work with > multiple named define() calls in them (that depend on each other), without > any extra code, but I believe this approach definitely has some pros to it.
> Taka
> On Fri, Mar 2, 2012 at 11:31 AM, James Burke <jrbu...@gmail.com> wrote:
>> As Eric mentioned, we've talked a bit on this before. I favor just >> using a global require, but the folks that prefer not to use that, >> IIRC, John Hann and Rawld, I do not think have proposed something >> else. Using anything on define() seems like the incorrect place, as I >> mentioned in that thread that Eric mentioned.
>> Some requirejs specific notes below…
>> On Thu, Mar 1, 2012 at 1:02 PM, Taka Kojima <t...@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.
Standardizing this and implementing this actually solves Eric's bigger issue as well.
By requiring any file that defines more than one module to explicitly state at the top of the file what modules it defines, you are able to implement:
define("main", ["a","b","c"], function(a,b,c) {
});
Without worrying about the problem that comes up by deferring define() calls. This allows you to use define() out of the context of a "loaded js module/file".
I'll post a response in that other thread with a couple other ideas.
On Fri, Mar 2, 2012 at 1:30 PM, James Burke <jrbu...@gmail.com> wrote: > The very minor possible speed gain (which is dwarfed by any network > activity) is not worth the extra complication of expanding the API and > the burden on implementers to match. This has not come up as an issue > in real world scenarios.
> 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
> On Fri, Mar 2, 2012 at 11:55 AM, Taka Kojima <t...@gigafied.com> wrote: > > There is some overflow into those other discussions, but I was more > talking > > about this scenario:
> > In this scenario, we essentially have to halt all dependency lookup until > > the final define() call is made. This is somewhat unflexible and leads to > > lesser speed overall (although in most cases, it will be negligible). It > > also stops me from doing any sort of async define call in the script.
> > If we replaced the define call for "c" with the following:
> > RequireJS would try to look elsewhere for "c", even though it is defined > > later on in the file, just not immediately.
> > d depends on a, b and c, which are defined later in the file, so how > else do > > we solve this? Using existing functionality it could be something like > this:
> > I don't even know if the above will currently work in RequireJS, but the > > gist of it is that at the top of every file we say "this file provides > > definitions for these modules".
> > It is more code and I was suggesting that we could simplify it into a a > > single function call with an array like:
> > define(["d", "a", "b", "c"]);
> > Doing something like the above allows us to not halt dependency > > lookup/fetching at any point the script's execution, and also allows for > > async calls to define().
> > This only applies to files with more than one named module definition in > > them, so in most scenarios these are files outputted by a > build/optimization > > tool.
> > This may be viewed as "going backwards", i.e. AMD loaders already work > with > > multiple named define() calls in them (that depend on each other), > without > > any extra code, but I believe this approach definitely has some pros to > it.
> > Taka
> > On Fri, Mar 2, 2012 at 11:31 AM, James Burke <jrbu...@gmail.com> wrote:
> >> As Eric mentioned, we've talked a bit on this before. I favor just > >> using a global require, but the folks that prefer not to use that, > >> IIRC, John Hann and Rawld, I do not think have proposed something > >> else. Using anything on define() seems like the incorrect place, as I > >> mentioned in that thread that Eric mentioned.
> >> Some requirejs specific notes below…
> >> On Thu, Mar 1, 2012 at 1:02 PM, Taka Kojima <t...@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.
On Fri, Mar 2, 2012 at 2:11 PM, Taka Kojima <t...@gigafied.com> wrote: > Standardizing this and implementing this actually solves Eric's bigger issue > as well.
> By requiring any file that defines more than one module to explicitly state > at the top of the file what modules it defines, you are able to implement:
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.
In Needs, all dependencies are loaded recursively, and all factory functions are executed at the time of the define call, this may not be how RequireJS does it. In RequireJS do you add all defines() to an object, then only invoke those define calls when/if they are needed?
So, now your response makes sense. In Needs, doing this:
define("main", ["a","b","c"], function(a,b,c) {
});
would work to replace the global-level require() entry point, however in RequireJS this wouldn't work because while "main" is defined, neither it's factory function or dependencies have been loaded.
I guess we have two rather different approaches then. I see no mention in the spec of how to handle the loading/execution of module dependencies/factory functions.
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 see where not executing the factory function in the actual define() might make sense, however at least in my use cases, my factory functions don't really do much that would entail any sort of undesirable overhead. Anything expensive happens in methods and objects returned from the factory function.
On Fri, Mar 2, 2012 at 2:25 PM, James Burke <jrbu...@gmail.com> wrote: > On Fri, Mar 2, 2012 at 2:11 PM, Taka Kojima <t...@gigafied.com> wrote: > > Standardizing this and implementing this actually solves Eric's bigger > issue > > as well.
> > By requiring any file that defines more than one module to explicitly > state > > at the top of the file what modules it defines, you are able to > implement:
> 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.
> As Eric mentioned, we've talked a bit on this before. I favor just > using a global require, but the folks that prefer not to use that, > IIRC, John Hann and Rawld, I do not think have proposed something > else.
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.
> On Thu, Mar 1, 2012 at 1:02 PM, Taka Kojima<t...@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.
>> 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.
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().
On Fri, Mar 2, 2012 at 3:21 PM, Taka Kojima <t...@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.
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.
> On Fri, Mar 2, 2012 at 3:21 PM, Taka Kojima<t...@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.
> 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 think it would be a bad idea for the spec to mandate this sort of thing. Personally my AMD loaders call the factories on-demand, not when the define method is called.
<eric.brechem...@gmail.com> wrote: > 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()
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.
<richardabackho...@gmail.com> wrote: > I think it would be a bad idea for the spec to mandate this sort of thing. > Personally my AMD loaders call the factories on-demand, not when the define > method is called.
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.
> 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.
The more I think about it, the more it makes sense to do it this way, as it would provide the most consistency between the non-built version of your app, and the built version.
When modules are defined in individual files (i.e. during the dev process), the factory functions only get invoked when they are needed. Even if this technically happens during define(), modules aren't loaded unless they are required() somewhere in your application. Thus it behaves much like only invoking the factory function upon said module being required.
When in production and using a built file, you may provide definitions for a lot of modules up front. Having the factory methods execute only when they are needed makes the most sense, as this is how you would expect it to behave locally during development, so it should behave the same way when built.
For a lot of cases it won't matter, but having that consistency there makes sense and I think it is something that should be standardized.
return function () { console.log(window.something); }
});
During dev, if I do:
require(["module/a"], function (a) { a();
});
console.log() will print "a"
However, if I built module/a with module/b, during production (if I was executing the factory functions upon define, vs when they are required), console.log() will print "b".
Obviously, the above is a very good example of HOW NOT to write code, but it illustrates the point. Anything that promotes consistency between an AMD-based project between dev and production is something that should be standardized.
Bad code or not, I shouldn't get entirely different behavior if I'm running my site with anonymous modules pre-build, or concat & minified production build.
There's also the matter of pre-fetching dependencies, which I think is something that doesn't have to be standardized. If some loader wants to prefetch dependencies, found in a built file, then I think that's fine. If other loaders prefer to only fetch the needed modules when actually required, I think that is also fine.
On Sun, Mar 4, 2012 at 9:17 PM, James Burke <jrbu...@gmail.com> wrote: > On Sun, Mar 4, 2012 at 6:05 PM, Richard Backhouse > <richardabackho...@gmail.com> wrote: > > I think it would be a bad idea for the spec to mandate this sort of > thing. > > Personally my AMD loaders call the factories on-demand, not when the > define > > method is called.
> 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.
> FWIW, if we were to try to standardize something, I could see standardizing the behavior you are using -- only execute factories on 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?
<dome...@domenicdenicola.com> wrote: > 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?
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.
> On Sat, Mar 3, 2012 at 12:41 AM, Eric Br chemier > <eric.brechem...@gmail.com> wrote: >> 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() > 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 agree, but I can't come up with a rational argument that it should be this way other than taste and history. James--do you have some specific reasons for this opinion?
> 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.
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.
> On Fri, Mar 2, 2012 at 3:21 PM, Taka Kojima<t...@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.
I've implemented bdLoad/dojo so that module eval order is well-defined whether or not you are loading a built or unbuilt code stack.
Recall from Taka's earlier message in this thread, this code:
Presumably, the intention is a resource that contains modules a-d. However, I believe this design is flawed because it makes the assumption that any "source" resource contains exactly one define application *and nothing else*. Usually, this is the case. But there is no reason is it a requirement, and a module may contain other code before and/or after the define application.
The bdLoad/bdBuild/dojo build systems/loaders solve the problem by maintaining a client-side cache of modules that may be added to and then consumed as required. Assuming the example above had the purpose of defining "d" and aggregating "a", "b", and "c", the dojo builder output would look like this:
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});
When the loader processes the require call, it notices it is a configuration application that provides a cache value, and adds the modules a, b, and c to the module cache...it does not execute those functions...e.g. it just adds the property "a" with the function value to the cache (there is some special stuff that goes on to deal with mapping...but we can talk about that later). Multiple cache configs can be consumed.
Then the define application is processed as usual.
Finally, when some require chain actually requires any of "a", "b", of "c", the loader first looks in the cache before downloading...if found, *then* it evaluates the function...thereby causing unbuilt and built to work *exactly* the same.
> 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});
This makes sense Rawld, it's along the same lines of how I am refactoring Needs to work.
However, in my implementation the file still looks like this:
Upon define(), a module checks to see if it's id exists in a _requiredModules array. If the module is in _requiredModules, then its factory function is invoked, otherwise, it goes to the cache.
Whenever you call require(), the modules you require get pushed to _requiredModules. My implementation of define() uses require() to get dependencies, so this works well recursively.
On Mon, Mar 5, 2012 at 11:26 AM, Rawld <rg...@altoviso.com> wrote: > ** > On 03/04/2012 05:21 PM, James Burke wrote:
> On Fri, Mar 2, 2012 at 3:21 PM, Taka Kojima <t...@gigafied.com> <t...@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.
> I've implemented bdLoad/dojo so that module eval order is well-defined > whether or not you are loading a built or unbuilt code stack.
> Recall from Taka's earlier message in this thread, this code:
> Presumably, the intention is a resource that contains modules a-d. > However, I believe this design is flawed because it makes the assumption > that any "source" resource contains exactly one define application *and > nothing else*. Usually, this is the case. But there is no reason is it a > requirement, and a module may contain other code before and/or after the > define application.
> The bdLoad/bdBuild/dojo build systems/loaders solve the problem by > maintaining a client-side cache of modules that may be added to and then > consumed as required. Assuming the example above had the purpose of > defining "d" and aggregating "a", "b", and "c", the dojo builder output > would look like this:
> 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});
> When the loader processes the require call, it notices it is a > configuration application that provides a cache value, and adds the modules > a, b, and c to the module cache...it does not execute those > functions...e.g. it just adds the property "a" with the function value to > the cache (there is some special stuff that goes on to deal with > mapping...but we can talk about that later). Multiple cache configs can be > consumed.
> Then the define application is processed as usual.
> Finally, when some require chain actually requires any of "a", "b", of > "c", the loader first looks in the cache before downloading...if found, > *then* it evaluates the function...thereby causing unbuilt and built to > work *exactly* the same.
On Mon, Mar 5, 2012 at 11:06 AM, Rawld <rg...@altoviso.com> wrote: > On 03/04/2012 09:14 PM, James Burke wrote: >> 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 agree, but I can't come up with a rational argument that it should be this > way other than taste and history. James--do you have some specific reasons > for this opinion?
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."
On Mon, Mar 5, 2012 at 11:26 AM, Rawld <rg...@altoviso.com> wrote: > The bdLoad/bdBuild/dojo build systems/loaders solve the problem by > maintaining a client-side cache of modules that may be added to and then > consumed as required. Assuming the example above had the purpose of defining > "d" and aggregating "a", "b", and "c", the dojo builder output would look > like this:
> 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});
> When the loader processes the require call, it notices it is a configuration > application that provides a cache value, and adds the modules a, b, and c to > the module cache...it does not execute those functions...e.g. it just adds > the property "a" with the function value to the cache (there is some special > stuff that goes on to deal with mapping...but we can talk about that later). > Multiple cache configs can be consumed.
> Then the define application is processed as usual.
> Finally, when some require chain actually requires any of "a", "b", of "c", > the loader first looks in the cache before downloading...if found, *then* it > evaluates the function...thereby causing unbuilt and built to work *exactly* > the same.
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.
> 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. > :)
Right...iirc, when Kris originally wrote the spec he named it modules/asynchronous definitions...and I referred to it as MAD a few times in IRC :)
>>> 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.
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."
I'm all for a global require, it's actually fairly easy to augment the global require too, something like:
if (require) {
_globalReq = require;
require = function () { if (arguments.length > 1) { return req.apply(this, arguments);
}
else { return _globalReq.apply(this, arguments);
} } }
else { require = req;
}
Where `req` is a reference to the AMD version of the global require, I think if implemented this way, people would get used to it fairly easily.
I mean, when writing JS on the server-side (or client-side for that matter) and you see code like this:
someFunc("someArg", function () {
});
Anybody that has been writing JavaScript for more than a day could tell you that someFunc is executing something async and wants the function it provided as the second argument to be invoked after someFunc does its thing.
On Mon, Mar 5, 2012 at 8:14 PM, Rawld <rg...@altoviso.com> wrote: > On 03/05/2012 05:15 PM, James Burke wrote:
>> 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. >> :)
> Right...iirc, when Kris originally wrote the spec he named it > modules/asynchronous definitions...and I referred to it as MAD a few times > in IRC :)
> 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.
> 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."
On Mon, Mar 5, 2012 at 10:38 PM, Taka Kojima <t...@gigafied.com> wrote: > I'm all for a global require, it's actually fairly easy to augment the > global require too, something like:
> Where `req` is a reference to the AMD version of the global require, I > think if implemented this way, people would get used to it fairly easily.
> I mean, when writing JS on the server-side (or client-side for that > matter) and you see code like this:
> someFunc("someArg", function () {
> });
> Anybody that has been writing JavaScript for more than a day could tell > you that someFunc is executing something async and wants the function it > provided as the second argument to be invoked after someFunc does its thing.
> Taka
> On Mon, Mar 5, 2012 at 8:14 PM, Rawld <rg...@altoviso.com> wrote:
>> On 03/05/2012 05:15 PM, James Burke wrote:
>>> 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. >>> :)
>> Right...iirc, when Kris originally wrote the spec he named it >> modules/asynchronous definitions...and I referred to it as MAD a few times >> in IRC :)
>> 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.
>> 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."