but I will summarize and provide some background here for AMD folks
not familiar with path resolution of module IDs.
Background
----------------
For an AMD loader to work in the browser efficiently, it should only
do one URL lookup for the module. This is different from traditional
CommonJS Modules 1.1 spec loaders on the server, where they normally
use a require.paths array to search for modules.
AMD supports the CommonJS type of module IDs that look like
'some/module', which gets mapped to an URL using some configuration in
the loader.
This normally involves using a "baseUrl" and appending the module ID
plus '.js' to create the path. So, for 'some/module', the URL ends up
being baseUrl + 'some/module.js'.
There are a few AMD implementations, requirejs, curl, bdload/dojo
loader that allow mapping *part* of a module ID to a different path
than what would normally be used if just using the baseUrl.
For example, in requirejs, this configuration call would result in an
URL of baseUrl + 'thirdparty/special/some/module.js':
require({
paths: {
'some': 'thirdparty/special/some'
}
});
Some loaders, like requirejs and dojo, support configuring the
location of a set of modules according to the CommonJS Packages spec's
use of 'main' and 'lib' properties:
http://requirejs.org/docs/api.html#packages
I now believe the 'main' and 'lib' properties of the CommonJS Packages
spec to be bad ideas. Node 0.4 does support the 'main' property.
However Node removed support for 'lib' in 0.4 because of the extra
path magic it required. I agree with this conclusion, as I believe it
contributes to this relative ID problem.
Summary of Issue:
----------------
If a module does a require('foo') and then foo.js has a
require('./bar'), how should './bar' be resolved to an URL?
Options:
----------------
1) "Relative to module ID": resolve the relative module ID, './bar',
relative to the reference ID, 'foo'. So, the relative module ID gets
converted to 'foo/bar' and then the path/package configuration is used
to resolve it.
2) "Relative to module URL": Resolve the relative ID './bar' relative
to the reference ID's URL. So, in the simple case: URL prefix +
'foo.js' + './bar.js' (but of course cleaned up to be a real path).
Problems:
----------------
There are many configurations where #1 and #2 result in the same
value, so it does not matter. However, there are two cases where it
makes a difference:
1) CommonJS Package's 'lib' directory is in play. In the example, if
'foo' is a CommonJS package, and its main: 'foo.js' and 'lib' is set
to 'scripts', then the paths get resolved to:
Option 1: foo/scripts/bar.js
Option 2: foo/bar.js
I suggest we follow Node's lead here and discourage AMD
implementations from implementing 'lib' support. This removes the
problem with this discrepancy, and makes implementation easier all
around.
2) paths: configuration. There could be this type of configuration set up:
require({
paths: {
'foo/bar': 'overrides/foo/bar'
}
});
The resulting URLs:
Option 1: baseUrl + 'overrides/foo/bar.js'
Option 2: baseUrl + 'foo/bar.js'
I believe Option 1 is the desirable behavior, because this allows
proper overriding of modules. This is particularly useful if you are
building a toolkit, and you know that you can deploy a different
version of 'arrayExtras' depending on the deployment scenario (if only
webkit, then map 'arrayExtras' to an empty file). If option 2 is used,
you will *not* be able to override the path used if './arrayExtras' is
used.
Summary
----------------
Those were the issues I were able to come up with, but I may have
missed something so please point it out. However, based on this
information, I favor using Option 1, 'relative to module ID'.
This is actually a change for RequireJS, and I will update the code to
reflect the change if other implementers agree. As part of that
update, I would remove CommonJS Package 'lib' support too.
The original reason RequireJS supports Option 2 'relative to module
URL' was because of this issue:
https://github.com/jrburke/requirejs/issues/51
but I believe with the removal of 'lib' support issue #51 goes away.
James
Options:
----------------1) "Relative to module ID": resolve the relative module ID, './bar',
relative to the reference ID, 'foo'. So, the relative module ID gets
converted to 'foo/bar' and then the path/package configuration is used
to resolve it.
Hmm, I do not think so? The example I have was that something asks for
require('foo'). This could be done like so too: define(['foo'],...) or
require(['foo']).
In that case, foo is a top-level ID. The module asking for it does not
matter for the path resolution?
James
paths: {'one': 'foo/bar/one'}
Hmm, I got lost here. Module IDs are not actual URL paths. They can be
used in a path lookup, and you can normally guess where the module is
at based on the ID, but for instance, in a built file, there is no
path lookup because multiple modules are included in one file.
I feel like there is a disconnect, I still do not see how the module
that require's 'foo' affects the module resolution in either option,
given that 'foo' is a non-relative ID.
> consider this
> file https://github.com/jrburke/requirejs/blob/master/tests/relative/foo/bar/one.js and
> lets say https://github.com/jrburke/requirejs/blob/master/tests/relative/ is
> my baseURl and i had an entry in the path map for
> paths: {
> 'one': 'foo/bar/one.js'
> }
> if load 'one' and it has the dependency './two' - which file will it get?
> it won't be one/two.js but it will be <parent of one>/two.js
> option a)
> - https://github.com/jrburke/requirejs/blob/master/tests/relative/two.js
> option b)
> - https://github.com/jrburke/requirejs/blob/master/tests/relative/foo/bar/two.js
> fwiw, i like option b.
That specific example has a problem because
tests/relative/foo/bar/one.js defines a named module, 'foo/bar/one',
so mapping 'one' to 'foo/bar/one' would cause an error then asking for
require('one') will cause an error.
But it does point out why using module ID instead of URL is useful in
a built situation: in that case, 'foo/bar/one' module asking for
'./two' means it can be found at the ID 'foo/bar/two', which would
work with a built file.
What am I missing?
James
I agree.
>
> Summary of Issue:
> ----------------
>
> If a module does a require('foo') and then foo.js has a
> require('./bar'), how should './bar' be resolved to an URL?
>
> Options:
> ----------------
>
> 1) "Relative to module ID": resolve the relative module ID, './bar',
> relative to the reference ID, 'foo'. So, the relative module ID gets
> converted to 'foo/bar' and then the path/package configuration is used
> to resolve it.
I'm confused and have the same observation that Ben has made. Let's consider a
specific foo.js:
// begin foo.js
define(["./bar", require], function(bar, require) {
// the foo module factory...
// stuff...
bar2= require("./bar");
require(["./bar"], funciton(bar3) {
// at this point bar===bar2===bar3
});
// more stuff...
});
// end foo.js
I believe:
1. The loader should deliver the same module for bar, bar2, and bar3. Those
require's are not required and bad form...they are there solely to demonstrate
this point.
2. The absolute module id implied by "./bar" for Option 1 is "bar". This is
because modules have an implied root, so "foo" is, at least heuristically,
equivalent to "/foo" in the module id space (that's not a URL), and "." is the
parent module of the reference module (note: I don't like that, but I lost
that argument months ago).
>
> 2) "Relative to module URL": Resolve the relative ID './bar' relative
> to the reference ID's URL. So, in the simple case: URL prefix +
> 'foo.js' + './bar.js' (but of course cleaned up to be a real path).
So, here are you saying "." is the directory that holds foo?
>
> Problems:
> ----------------
>
> There are many configurations where #1 and #2 result in the same
> value, so it does not matter. However, there are two cases where it
> makes a difference:
>
> 1) CommonJS Package's 'lib' directory is in play. In the example, if
> 'foo' is a CommonJS package, and its main: 'foo.js' and 'lib' is set
> to 'scripts', then the paths get resolved to:
>
> Option 1: foo/scripts/bar.js
> Option 2: foo/bar.js
>
> I suggest we follow Node's lead here and discourage AMD
> implementations from implementing 'lib' support. This removes the
> problem with this discrepancy, and makes implementation easier all
> around.
I advocate the following rule:
"When you specify a relative module id, it is relative to the reference
module's id. No further mapping of the module id is applied"
Since the loader must compute a non-relative module id for every module, the
reference module id is well-defined.
Since no further mapping is applied, loaders could still understand the lib
and main package config variables...with respect to *non-relative* module ids.
>
> 2) paths: configuration. There could be this type of configuration set up:
>
> require({
> paths: {
> 'foo/bar': 'overrides/foo/bar'
> }
> });
>
> The resulting URLs:
>
> Option 1: baseUrl + 'overrides/foo/bar.js'
> Option 2: baseUrl + 'foo/bar.js'
>
> I believe Option 1 is the desirable behavior, because this allows
> proper overriding of modules. This is particularly useful if you are
> building a toolkit, and you know that you can deploy a different
> version of 'arrayExtras' depending on the deployment scenario (if only
> webkit, then map 'arrayExtras' to an empty file). If option 2 is used,
> you will *not* be able to override the path used if './arrayExtras' is
> used.
You can still solve this problem with option 1. If you are building a toolkit,
then the toolkit will have a top-level module id, say "dojo". Then, for
example, from the reference module "dojo/lang" you could specify the relative
module "./array", which resolves to "dojo/array", which can be mapped in paths
as usual to a different URL.
Here's why relative ids should be relative to the reference module's id, not
the reference module's url....
The mapped version of array (to continue the example) may have the same deps
vector as the unmapped version of array--in fact, it almost always will. Let's
say it has the deps ["./kernel"].
If the mapped version of array is located in the same directory as the
unmapped version, then either method will work.
But if the mapped version is located someplace else and the loader tries to
resolve "./kernel" with respect to the somplace else URL, then the system will
fail. otoh, if the loader resolves "./kernel" with respect to the reference
module id, in this case still "dojo/array" irrespective of its actual URL,
then the proper kernel module will be used.
>
> Summary
> ----------------
>
> Those were the issues I were able to come up with, but I may have
> missed something so please point it out. However, based on this
> information, I favor using Option 1, 'relative to module ID'.
>
> This is actually a change for RequireJS, and I will update the code to
> reflect the change if other implementers agree. As part of that
> update, I would remove CommonJS Package 'lib' support too.
>
> The original reason RequireJS supports Option 2 'relative to module
> URL' was because of this issue:
> https://github.com/jrburke/requirejs/issues/51
With the clarification given above, option 1 can support issues/51.
I support option 1.
Best,
Rawld
Yeah, so I *really* messed up on that example: require('./bar') would
resolve to just 'bar', since 'foo' is a top-level ID, *not* as I said,
'foo/bar'. Very sorry for muddying the waters.
>>
>> 2) "Relative to module URL": Resolve the relative ID './bar' relative
>> to the reference ID's URL. So, in the simple case: URL prefix +
>> 'foo.js' + './bar.js' (but of course cleaned up to be a real path).
>
> So, here are you saying "." is the directory that holds foo?
My bad again. The resolved URL for './bar' would be URL prefix +
'bar.js', which would be the same as option 1 unless a paths:
configuration for 'bar' was in play.
> I advocate the following rule:
>
> "When you specify a relative module id, it is relative to the reference
> module's id. No further mapping of the module id is applied"
I think the "no further mapping of the module ID is applied" is a bit
confusing, or at least does not add any more guidance for relative ID
resolution: it seems enough to say "resolve the relative ID relative
to the reference module ID". Then, that resolved module ID gets the
configuration mapping applied to generate its URL.
> Since the loader must compute a non-relative module id for every module, the
> reference module id is well-defined.
>
> Since no further mapping is applied, loaders could still understand the lib
> and main package config variables...with respect to *non-relative* module ids.
When "lib" configuration is in play, this does not work out, and this
is the cause of the issue #51 in requirejs. Consider a package named
pkgName that has main: 'main.js' and lib: 'lib'.
* Something does a require('pkgName')
* inside pkgName/main.js there is a require('./lib/support')
With Option 1, the resolved relative module ID would be
'pkgName/lib/support'. However, given 'lib' rules, this would be
mapped to a 'pkgName/lib/lib/support.js' URL, which is wrong.
But this is just evidence to me that lib is a bad idea, and we should
not support it anymore.
> Here's why relative ids should be relative to the reference module's id, not
> the reference module's url....
>
> The mapped version of array (to continue the example) may have the same deps
> vector as the unmapped version of array--in fact, it almost always will. Let's
> say it has the deps ["./kernel"].
>
> If the mapped version of array is located in the same directory as the
> unmapped version, then either method will work.
>
> But if the mapped version is located someplace else and the loader tries to
> resolve "./kernel" with respect to the somplace else URL, then the system will
> fail. otoh, if the loader resolves "./kernel" with respect to the reference
> module id, in this case still "dojo/array" irrespective of its actual URL,
> then the proper kernel module will be used.
Agreed, however, I think the tricky situation is the one Ben
originally raised in the dojo-contributors list is this:
I want to create an 'array' module. However I have a paths:
configuration with 'array': 'dojo/array', and 'dojo/array' has a
dependency on './kernel'.
So, in my project, when I do require('array'), the relative ID
'./kernel' in Option 1 will be resolved to 'kernel' (a top-level ID)
which does not exist. With Option 2, it would find the right
'dojo/kernel.js' file.
However, with Option 2, the developer could *never* use paths: config
to map 'dojo/kernel' to another file, since the relative ID is
resolved via the URL -- paths config cannot be used as part of that
URL resolution.
I believe Ben's case should be solved by having his 'array' to just
delegate to dojo/array:
//array.js:
define('[dojo/array'], function (array){
return array;
});
Because losing the ability to map 'dojo/kernel' to some other file is
a greater loss in capability, and when considering built/optimized
files with more than one module in it, those modules use module IDs to
name themselves, not URL paths.
Rawld, which I think you agree with, but just trying to illustrate the
tradeoffs better relative to Ben's original question.
James
Right.
>
> What exactly do you mean by "well-defined"?
Just that it has an unabiguous name known to the loader: given a module-id,
it can refer to exactly one module within any context.
From my perspective:
* both are fine.
* the exsitence or not of paths doesn't affect the discussion.
I would rephrase the options as follows:
1. A relative module id is resolved with respect to the reference module's id.
2. A relative module id is resolved with respect to the reference module's
URL.
I strongly support [1].
Best,
Rawld
Yeah, so I *really* messed up on that example: require('./bar') would
resolve to just 'bar', since 'foo' is a top-level ID, *not* as I said,
'foo/bar'. Very sorry for muddying the waters.
I believe Ben's case should be solved by having his 'array' to just
delegate to dojo/array://array.js:
define('[dojo/array'], function (array){
return array;
});
Because losing the ability to map 'dojo/kernel' to some other file is
a greater loss in capability, and when considering built/optimized
files with more than one module in it, those modules use module IDs to
name themselves, not URL paths.
I was trying to say that the module id is not further transformed. It may or
may not be used as an argument to find the URL that addresses the resource
that defines the module given by the module id. For example, maybe the module
has already been published to the loader directly by some method other than
having the loader go retrieve the resource.
>
> > Since the loader must compute a non-relative module id for every module,
> > the reference module id is well-defined.
> >
> > Since no further mapping is applied, loaders could still understand the
> > lib and main package config variables...with respect to *non-relative*
> > module ids.
>
> When "lib" configuration is in play, this does not work out, and this
> is the cause of the issue #51 in requirejs. Consider a package named
> pkgName that has main: 'main.js' and lib: 'lib'.
>
> * Something does a require('pkgName')
> * inside pkgName/main.js there is a require('./lib/support')
>
> With Option 1, the resolved relative module ID would be
> 'pkgName/lib/support'. However, given 'lib' rules, this would be
> mapped to a 'pkgName/lib/lib/support.js' URL, which is wrong.
Well, we're making up the rules here...right?:)
So, just for the sake of argument, apply my rule:
"When you specify a relative module id, it is relative to the reference
module's id. No further mapping of the module id is applied"
1. The reference module id is "pkgName/main".
2. The relative module id with respect to [1] is "./lib/support"
Therefore the absolute module id implied by [2] is:
"pkgName/main/.././lib/support" =>
"pkgName/lib/support"
which is exactly what we want.
>
> But this is just evidence to me that lib is a bad idea, and we should
> not support it anymore.
I will never argue in favor of lib. I, also, strongly dislike main and lib and
don't see the point. I agree with Kris Zyp...just use paths...keep it simple.
>
> > Here's why relative ids should be relative to the reference module's id,
> > not the reference module's url....
> >
> > The mapped version of array (to continue the example) may have the same
> > deps vector as the unmapped version of array--in fact, it almost always
> > will. Let's say it has the deps ["./kernel"].
> >
> > If the mapped version of array is located in the same directory as the
> > unmapped version, then either method will work.
> >
> > But if the mapped version is located someplace else and the loader tries
> > to resolve "./kernel" with respect to the somplace else URL, then the
> > system will fail. otoh, if the loader resolves "./kernel" with respect
> > to the reference module id, in this case still "dojo/array" irrespective
> > of its actual URL, then the proper kernel module will be used.
>
> Agreed, however, I think the tricky situation is the one Ben
> originally raised in the dojo-contributors list is this:
>
> I want to create an 'array' module. However I have a paths:
> configuration with 'array': 'dojo/array', and 'dojo/array' has a
> dependency on './kernel'.
>
> So, in my project, when I do require('array'), the relative ID
> './kernel' in Option 1 will be resolved to 'kernel' (a top-level ID)
> which does not exist. With Option 2, it would find the right
> 'dojo/kernel.js' file.
I think that's a defective configuration...if that's what Ben really wants (I
think what he really wants is a non-ambiguous way to do rational mappings).
I think he is asking, "how do a replace a single module, for example
"dojo/array", in the middle of a hierarchy of modules?"
If that's the question then my answer is paths looks like:
paths:{
"dojo/array":"path/to/replacement/module"
}
Relative paths in the replacement module are relative to module id, not the
url, so, e.g., "./kernel" resolves to the dojo/kernel in the dojo hierarchy,
not in the replacement hierarchy.
>
> However, with Option 2, the developer could *never* use paths: config
> to map 'dojo/kernel' to another file, since the relative ID is
> resolved via the URL -- paths config cannot be used as part of that
> URL resolution.
Agree.
To put a fine point on in, if the replacement wants to reference modules from
the original hierarchy, just specify a relative path (e.g., "./kernel"). If
the replacement also wants some modules outside of the original hierachy, then
say so, explicitly (e.g., "myReplacement/kernel"). Of course you can further
map myReplacement with paths.
>
> I believe Ben's case should be solved by having his 'array' to just
> delegate to dojo/array:
>
> //array.js:
> define('[dojo/array'], function (array){
> return array;
> });
Agree...strongly
>
> Because losing the ability to map 'dojo/kernel' to some other file is
> a greater loss in capability, and when considering built/optimized
> files with more than one module in it, those modules use module IDs to
> name themselves, not URL paths.
>
> Rawld, which I think you agree with, but just trying to illustrate the
> tradeoffs better relative to Ben's original question.
Best,
Rawld
It's important to remember that all of the requirejs tests work correctly
either way [I'm pretty sure about this]. I know James if very good about
adding a test case for each of these kinds of decisions. In other words, this
hasn't been a big issue until now.
I'd even argue that James hasn't committed--certainly not strongly by
specifying a test to demonstrate correctness of a particular algorithm--to
either option so far. If you buy that argument, then nobody should complain
about clarifying an undecided area.
Lastly, the *great* part of this mailing list is that we have several
implementers. I'm committed to making dojo and bdLoad compat with RequireJS.
As long as we make rational, justifiable decisions, it seems we have enough
critical mass that others will follow.
Best,
Rawld
Before I respond. Can you confirm that you want to further map the module id
to another module id? Or are you really asking about transforming the module
id to a url?
>
> > But if the mapped version is located someplace else and the loader tries
> > to resolve "./kernel" with respect to the somplace else URL, then the
> > system will fail.
>
> Of course this should fail. Why would anybody separate a module from
> its dependencies? This makes no sense to me.
Well, that's exactly how requirejs works today.
Again, the question is...is "./kernel" resolved with respect to the reference
module id or module url?
You are making the assumption that array is the only module that depends on
kernel (or, put another way, that kernel only serves array). This may not be
the case. If you are trying to map/replace a single module in a hierarchy,
this is not the case.
If you are trying to map a hierarchy, that's a package. Just point the package
location to a different place if you want a different package.
A package is not about lib and main...those are side issues. A package is a
hierarchy of interdependent modules.
>
>
> In a truly interoperable, modular world, this should work:
>
> // folder structure:
> js/
> some/
> hawt/
> array.js
> kernel.js
>
> // config:
> require({
> baseUrl: "js",
> paths: {
> "array": "some/hawt/array"
> }
> });
I consider this to be a defective configuration because you're mapping a top-
level name (array) into a module in the middle of a package. hawt is a package
because it's clearly a tree of interdependent modules.
>
> // "main" module:
> require(["array"], function (array) {
> // use my standardized array abstraction in here
> // notice in my dep list I am not referring to some/hawt/array
> // or dojo/array or yui/array etc.
> });
>
> // js/some/hawt/array.js
> define(["./kernel"], function (kernel) {
> // use kernel and return a standardized array abstraction
> // (like dojo does already)
> });
>
> If "No further mapping of the module id is applied", then the above
> can't work because the loader will look for kernel.js at "js/
> kernel.js" (no mapping) when it is actually located at "js/some/hawt/
> kernel.js". If we apply the existing mapping rules (as found in
> RequireJS 0.24 and curl.js 0.4.3), kernel.js will be found at "js/some/
> hawt/kernel.js" where we would expect it.
No, I wouldn't expect it...but I wouldn't give the defective config either.
Also, dojo, one of the original Javascript module systems wouldn't expect
that. More below.
>
> Tomorrow, when I discover I want to start using dojo instead of the
> some/hawt framework, I can change my paths config:
>
> require({ paths: { "array": "dojo/array" }, baseUrl: "js" });
>
> At JSCONF 2011, I talked about being able to write your code to a
> standardized API using this straightforward method of mapping
> standardized abstractions (such as "dojo/array" or "dojo/Sizzle") into
> implementation-agnostic names (e.g. "array" or "querySelectorAll") --
> and even quickly demoed it. People got very, very excited by this.
> Rebecca also showed a code example that exemplified this and advocated
> for it.
OK. But if your standardized abstraction requires a set of interdependent
modules, that's a package. If you want to use a single name (like array), then
that's the purpose of the package main config variable...
change your config to...
require({
baseUrl: "js",
packages:[{
name:"array",
main:"./array",
location:"some/hawt"
}]
})
> This is what most developers want from modules -- well, the developers
> that aren't zealots or fanboys for a single framework want this.
Everybody wants a good module system. Module systems are hard to get right and
have trade-offs. Any module system that I've had to use over the years has
areas that people--smart people, not just zealots--strongly disagree with.
Also, conference people getting excited in not evidence of good design.
>
> And frankly, I still don't know what the problem is. I have yet to
> see a use case that forces this: "No further mapping of the module id
> is applied". Every use case or code snippet I've seen in this thread
> so far works perfectly fine in curl.js.
>
> What isn't working today? Why do we need these new rules that break
> current, desirable functionality?
Its an established cannon of computer science that good design places a high
value on conceptual integrity. You are advocating a system where some kinds of
ids in deps vectors (relative ids) don't really specify a module id, but
rather a url, while others (absolute ids) don't specify a url, but rather a
module id. To me, that lacks conceptual integrity. Heck, it's possible that
some loader/systems may never resolve to URLs...then what's the rule?
And, tell me, what is the module id of "./kernel" with respect to the module
array. Give me a rule/process to compute it. So far, with option 2, I've only
seen a rule to find it's URL.
I advocate:
* ids--all ids--in deps vectors are module ids
* the purpose of a loader is to map a module id to a value
This, to my eye, has conceptual integrity.
Let me solve the problem you gave above and point out a few things along the
way.
The "hawt" tree clearly indicates a set of modules that
* are interdependent
* publish some public, perhaps interchangeable, API
That's a package, not a module. I would name the package "hawt" and configure
accordingly.
require({
baseUrl:"js",
packages:[{
name:"hawt",
location:"some/hawt"
}]
});
array.js is defined as you described above.
To use it, you require(["hawt/array"], //...
If you hate saying "hawt/array" and just want to say "array", then use the
main config value as I showed above.
Everything is peachy until the library "cool" is published which is way, way
better than hawt. But, you've got 300 source files that specify hawt...don't
want to change that. Well, you don't have too...just change the config and
you're good to go.
require({
baseUrl:"js",
packages:[{
name:"hawt",
location:"some/cool"
}]
});
Life is good again. But then a client needs an ever so slight extension to the
array impl in the cool lib. What's worse, the client is using--and wants to
continue to use--the cool library from a cdn that you can't touch. What you
need to do is somehow just replace one resource in cool library's hierarchy.
No problem, copy cool/array.js, make the changes, put it on your server and
then change the config to...
require({
baseUrl:"js",
packages:[{
name:"hawt",
location:"some/cool"
}],
paths:{
"hawt/array":"path/to/my/server"
}
});
Notice that the replacement will *still use the rest of cool's hierarchy*
without any further mapping.
Now, of course you could solve this if you use the "relative ids are with
respect to the reference module's url" option, but you'd have to rewrite and
then map the replacement array's dependency vector.
> What isn't working today? Why do we need these new rules that break
> current, desirable functionality?
>
> Please help me understand.
Actually, nothing isn't working today. Ben has brought up a spec ambiguity and
we're trying to agree on a resolution. Further, for most use cases, both
option 1 and option 2 end up having the same effect (though option 2 does not
specify how what the module id is of the resolved relative module)
But, this is important to decide. It is really foundational about what a
module loader is...does it provide a map from module id to module value with
machinery to instantiate modules as demanded by module id? If we say that URLs
can be specified in deps vectors (and that appears to be what you're
advocating) then I don't understand the abstraction we're trying to model.
Best,
Rawld
Depending on what your trying to do (map a module or a tree), each of option 1
or 2 is more or less work. It also depends on how you configure (as per my
other response).
To me, it's not about more/less work, but rather it's a question about what is
the abstraction we are modeling.
Right, to echo Rawld's point, this is an edge-case issue, for most
things it all works no matter what option you choose. However, this
edge case has highlighted how we think of module IDs and how they are
mapped to URLs. And I believe relative IDs are relative module IDs not
relative path constructs.
As to the case that breaks with "map relative to URL":
If dojo/array.js is:
define(['./kernel'], function (){})
In the case where you wanted to replace "dojo/kernel" with a different
implementation, you will not be able to do this with paths: config --
dojo/array.js will always use dojo/kernel.js, it will not look up
"dojo/kernel" for a path mapping and then generate the URL, it will
just use dojo/kernel.js. You would have to manually overwrite
dojo/kernel.js with a new file to replace the implementation. This
breaks one of the fundamental use cases for paths: configurations.
John, Ben: how does that sound? I know it places more work on making
adapters, but not being able to paths: map modules that are referenced
via relative ID seem to be a bigger loss. Not using module IDs means
the mapping rules are not applied uniformly and will cause confusion
-- it will result in tricky to track down runtime errors ("why isn't
dojo/array using my replacement for dojo/kernel, but this other module
does?").
If that sounds OK, the actions items I would like to do for requirejs:
* remove "lib" support for packages.
* make sure relative module IDs are resolved relative to the parent module ID.
* Create at least one test that confirms the change.
* This should also fix any weird build output that Ben discovered, but
if not, make sure that uses module IDs too.
James
> John, Ben: how does that sound? I know it places more work on making
> adapters, but not being able to paths: map modules that are referenced
> via relative ID seem to be a bigger loss. Not using module IDs means
> the mapping rules are not applied uniformly and will cause confusion
> -- it will result in tricky to track down runtime errors ("why isn't
> dojo/array using my replacement for dojo/kernel, but this other module
> does?").
>
> * make sure relative module IDs are resolved relative to the parent module ID.
is this the desired result?
require({
paths: {
"dojo/kernel" : "other_lib/kernel"
}
});
"dojo/kernel" -> "other_lib/kernel"
"foo/../dojo/kernel" -> "other_lib/kernel"
"dojo/./kernel" -> "other_lib/kernel"
"dojo/bar/../kernel" -> "other_lib/kernel"
"dojo/kernel/more" -> "other_lib/kernel/more" [?]
I like the idea of always mapping relative to parent module IDs but I think the last option "dojo/kernel/more" shouldn't be mapped since it doesn't match the "whole path ID", maybe add an option to add wildcards to paths IDs like "dojo/kernel/*" that way anything inside "dojo/kernel" would be mapped to "other_lib/kernel" and last option would make total sense.. it could be an easy way to replace a whole library by simply using adapters.
> "foo/../dojo/kernel" -> "other_lib/kernel"
This would not match since the ID is foo/dojo/kernel, path matches
start from the beginning of the string.
> "dojo/./kernel" -> "other_lib/kernel"
yes
> "dojo/bar/../kernel" -> "other_lib/kernel"
Would not match, same reason as foo/dojo/kernel
> "dojo/kernel/more" -> "other_lib/kernel/more" [?]
Would match the paths config.
> I like the idea of always mapping relative to parent module IDs but I think the last option "dojo/kernel/more" shouldn't be mapped since it doesn't match the "whole path ID", maybe add an option to add wildcards to paths IDs like "dojo/kernel/*" that way anything inside "dojo/kernel" would be mapped to "other_lib/kernel" and last option would make total sense.. it could be an easy way to replace a whole library by simply using adapters.
I have thought about supporting something like:
require({
paths: {
//Only applied if module name is exactly 'dojo/kernel'
'dojo/kernel': 'some/thing',
//Does not match 'dojo/kernel', but does match 'dojo/kernel/util'
'dojo/kernel/': 'other/dir'
}
});
So the presence of the slash on the end would signify only matching a
"directory name". I was preferring to not use a wildcard, since the
ending slash should be enough, but not sure if it is too subtle, and
not sure this is important enough to support vs. causing confusion on
typos.
James
Dustin
John, Ben: how does that sound? I know it places more work on making
adapters, but not being able to paths: map modules that are referenced
via relative ID seem to be a bigger loss. Not using module IDs means
the mapping rules are not applied uniformly and will cause confusion
-- it will result in tricky to track down runtime errors ("why isn't
dojo/array using my replacement for dojo/kernel, but this other module
does?").
If that sounds OK, the actions items I would like to do for requirejs:
* remove "lib" support for packages.
* make sure relative module IDs are resolved relative to the parent module ID.
* Create at least one test that confirms the change.
* This should also fix any weird build output that Ben discovered, but
if not, make sure that uses module IDs too.
James
I feel like lack of concrete examples are clouding my understanding of
this topic, so I really appreciate having “if you configure it like x
and require y, you resolve z” illustrations like these. Thanks, Miller
and James.
To continue along that vein, and to help support my understanding of
what the proposal is here, if someone configures an AMD-compliant
loader like:
require({
baseUrl: 'foo/',
paths: {
i18n: 'dojo/i18n',
'my/nls/app': 'other/nls/app',
'my/template': 'other/template',
'my/template.html': 'other/template2.html'
}
})
What will 'i18n' in require([ 'i18n!my/nls/app' ]) resolve to (both
module ID and path)?
What will dojo/i18n’s relative dependencies (like './main') resolve to
(both module ID and path)?
What will 'my/nls/app' resolve to in this example (both module ID and
path)?
What will 'dojo/text!my/template.html' resolve to in this example
(both module ID and path)?
What will 'dojo/text!./my/template.html' resolve to in this example
(both module ID and path)?
What will 'dojo/text!../my/template.html' resolve to in this example
(both module ID and path)?
I don’t mean to imply by any means that all of these behaviours should
definitely be defined by the spec (since as far as I am aware, any
data after the exclamation point is arbitrary and plugin-specific),
but I think it would good to be able to 1. explicitly define what, if
anything, is *outside* the spec in terms of resolving paths, and 2.
make sure that (if nothing else) there is some sort of de facto
agreement about how AMD plugins ought to handle common path/module
resolution cases, since these examples are all areas in which I’ve
experienced some wildly contradictory behaviour lately in existing
implementations.
Cheers,
i'll provide an answer to the best of my knowledge based on resolving relative ids as being relative to the module id. i'm open to correction of course and it would help if someone would confirm that i'm right as well if that's the case.
On Wednesday, May 11, 2011 8:14:14 PM UTC-4, C Snover wrote:I feel like lack of concrete examples are clouding my understanding of
this topic, so I really appreciate having “if you configure it like x
and require y, you resolve z” illustrations like these. Thanks, Miller
and James.
To continue along that vein, and to help support my understanding of
what the proposal is here, if someone configures an AMD-compliant
loader like:
require({
baseUrl: 'foo/',
paths: {
i18n: 'dojo/i18n',
'my/nls/app': 'other/nls/app',
'my/template': 'other/template',
'my/template.html': 'other/template2.html'
}
})
What will 'dojo/text!my/template.html' resolve to in this example
(both module ID and path)?
as you mention below, everything after the ! is up to the plugin to resolve. the plugin has require.toUrl at its disposal so we can discuss what would happen if require.toUrl was used because the behavior of require.toUrl for a plugin has been specified. see http://wiki.commonjs.org/wiki/Modules/LoaderPlugin#require.toUrl - however i'm unclear if require.toUrl('my/template.html') should use "my/template" as the module id or "my/template.html" and i see that you've loaded your example to highlight this ambiguity.first, the plugin with module id dojo/text would need to be resolvedmodule id: dojo/textpath: foo/dojo/text.jsnext, if dojo/text calls require.toUrl with "my/template.html" then i'm uncertain about the outcome. the 2 options aremodule id: my/template.htmlpath returned to the plugin: foo/other/template2
What will 'dojo/text!./my/template.html' resolve to in this example
(both module ID and path)?i'd like to provide an answer but this is impossible to say what will happen without knowing which module declared this relative dependency. i can say what should *not* happen - the relative id will not be relative to the plugin but rather it will be relative to the module that declared this dependency. without knowing the point of reference we can't figure out module id or path.
What will 'dojo/text!../my/template.html' resolve to in this example
(both module ID and path)?
I don’t mean to imply by any means that all of these behaviours should
definitely be defined by the spec (since as far as I am aware, any
data after the exclamation point is arbitrary and plugin-specific),
but I think it would good to be able to 1. explicitly define what, if
anything, is *outside* the spec in terms of resolving paths, and 2.
make sure that (if nothing else) there is some sort of de facto
agreement about how AMD plugins ought to handle common path/module
resolution cases, since these examples are all areas in which I’ve
experienced some wildly contradictory behaviour lately in existing
implementations.
Cheers,i believe that you've had the same shock that i've had recently when trying to load code with dojo's loader that was previously loaded with the requirejs loader. i concur that "wildly contradictory behaviour" describes what i observed.
>
> I want to map the module id to another module id. To me, the paths
> config parameter's purpose is to alias module ids. The concept that
> paths are just a way to map module ids to urls is not a universal
> given. In fact, out in the wild, it's being used to serve both
> purposes.
That's interesting. I never considered paths anything but a URL mapping
feature...I guess because of its name. But, I tend to agree, there is no
"authority" to say what paths is really supposed to be doing.
>
> I can think of two valid use cases for mapping module ids off the top
> of my head:
>
> 1) To shorten module ids when your third-party libraries are verbose:
>
> "dojo" <=> "third-party/dojo-1.6.0/dojo"
How is that different than the package.location config variable?
>
> 2) To remove explicit library names from common, standardized modules:
>
> "array" <=> "dojo/_base/array" // as the array module is named in dojo
> 1.6
Hmmm, to what standardization body are you referring? I'm not aware of any
"standardized modules".
>
>
> I can think of one use case for mapping a module id to a url:
>
> 1) To map to a remote location:
>
> "mylib" <=> "http://fastcdn.com/libs/mylib"
>
>
> Both of these scenarios need to work. No, creating an abstraction
> layer as a work-around for mapping module ids is not an option.
I'm not sure I see that mapping module ids isn't an abstraction layer...but
it's not worth a big discussion...let's just put this one on the "we may not
see it the same but it doesn't matter " stack.
>
> > > > But if the mapped version is located someplace else and the loader
> > > > tries to resolve "./kernel" with respect to the somplace else URL,
> > > > then the system will fail.
> > >
> > > Of course this should fail. Why would anybody separate a module from
> > > its dependencies? This makes no sense to me.
> >
> > Well, that's exactly how requirejs works today.
>
> I disagree. This is how the dojo loader behaves in the scenario I had
> painted. We must be miscommunicating about this point.
fwiw, I've implemented a has feature that lets the dojo loader do it either
way.
>
> > Again, the question is...is "./kernel" resolved with respect to the
> > reference module id or module url?
>
> No. There is a middle ground: module ids may be mapped / aliased.
OK. I agree with this...and have this feature in dojo. I just haven't talked
about it because we already are having a tough time with paths. It seems like
part of our (the group as a whole...not John and Rawld) problem is vocabular
and assumptions. I never considered paths a module id map...if that's what you
are proposing then my opinion changes.
[snip]
>
> Stepping back for a bit...
>
> Frameworks, such as dojo, may have public and private modules. The
> collection of public modules forms the public API of the package.
>
> In an interoperable world, public modules must be able to be used
> without the burden of the entire framework, but also must be able to
> have shared, private dependencies. (dojo/array having a dojo/kernel
> dependency is the example we've been using.)
>
> If you don't agree that dojo/array should be able to be used without
> the rest of the dojo package (i.e. it's a "defective configuration"),
> then there's a bigger problem to discuss since the dojo package (as
> implied by package.json) is the entire dojo framework. You may
> believe that a developer should embrace dojo as a whole, and maybe
> there is a lot of merit in doing so.
>
> However, I believe the developer should decide whether she/he wants
> the convenience of using and entire framework or cherry-picking the
> best modules. IMHO, she/he should be able to do this in an abstract
> way that doesn't require explicit package names (concrete dependencies
> infiltrating the code) or writing an abstraction layer (lots of work).
>
> As it stands right now, the only way to do this with dojo 1.6/
> RequireJS is to alias module ids ("array" <=> "dojo/_base/array"). If
> you remove the ability to alias module ids in the dojo 1.7 loader,
> then we're stuck writing an abstraction layer which sucks.
I understand and agree with your point. One of the issues is that a public
module, say dojo/array, may need to bring some private stuff along with it. So
we need a way to cherry pick dojo/array and have the private stuff come, but
not the rest of the public stuff. Is that what you're getting at?
[snip]
>
> You're proposed changes will break our valid use cases. Clearly,
> there must be a way to resolve the edge cases and not break our
> existing code. Does it make sense to separate the concepts of module
> id aliasing and module url mapping?
Though I'm not convinced of your assertion here, the idea that paths is a
module map, not a url map, changes the discussion significantly. I need to
think some more.
Best,
Rawld
As Ben pointed out, this one would match, since dojo/bar/../kernel
resolves to dojo/kernel. Sorry, when I read it I only parsed a single
dot, not both dots.
James
I'm not sure how this would work, allowing both kinds of mappings.
Maybe you could try to illustrate it, how you would apply the rules.
I am also unclear how you expect others to use your 'array' that is
mapped to 'dojo/array' -- it would require the end developer to set up
all the paths: mappings in their config to use it?
James
I am also unclear how you expect others to use your 'array' that is
mapped to 'dojo/array' -- it would require the end developer to set up
all the paths: mappings in their config to use it?
This is a good point, being able to use an IOC approach. Although, it
means it only works for top-level IDs. You cannot use an IOC model
inside a set of modules (commonly referred to as a package). Example:
Take the dojo package. Ideally relative modules IDs and anonymous
modules are used everywhere to allow the whole package to
renamed/moved to other directory name, for example, "myName". By using
relative IDs internally and using anonymous modules, the renaming
works.
However, if you wanted to build special versions of dojo that
substituted dojo/kernel, it would not be possible using URL
resolution, since all the modules use './kernel' as a dependency. The
primary use case for this internal mapping I would expect may be to do
browser-targeted builds, or to monkey-patch a problem with a module.
So I wonder if the package renaming of "dojo" to "myName" that is
supported is enough to get the IOC benefits you talk about?
A counterpoint may be that module mapping inside a package is not
really needed, although I have used that in the past with Dojo, so not
sure if it holds up as a counterpoint. But I'm open to the possibility
it is not.
> the last piece of the equation is to try and define some standard APIs that
> toolkits can work towards providing so that the need for adapters can be
> minimized. does anyone know of work being done to produce some common js
> APIs ;)
I would expect that if there were common APIs every made, they would
be placed under a "package" name, like "commonjs"? If dojo supported
them, then it would be a matter of mapping "commonjs" : "dojo".
James
I want to check in with everyone on this, and I would like to get it
resolved. I still favor resolving relative to module ID for the
following reasons:
1) It is still possible to provide the IOC/API mapping that
John/Brian/Ben bring up, as long as the mapping is restricted to a
"package" level mapping: So to use "dojo/array" as the implementation
for some common API, the common API needs to be scoped to a package.
So, it is possible to map "common/array" to "dojo/array" and things
still work by just mapping "common": "dojo".
2) It still allows single file mappings. So things like
"microlibraries" that just implement one small function without
complex dependencies can be aliased to other files.
3) It allows replacing the implementation of one module within a
package. Useful for building targeted builds of a package for
different environments/uses, or for monkey patching a single module in
a package.
Using URL mapping means:
Gives some more flexibility for #1 at the expense of not being able to
do #3. #2 works in both since it does not really involve relative IDs,
since microlibs probably would specify "top level" dependencies vs. a
relative one.
John/Brian/Ben: how does this sound? Any other feedback on the tradeoffs?
James
I think "./bar" relative to "foo" is "bar", and further...
"./B" relative to "A" => "A/.././B" => B
"./C" relative to "A/B" => "A/B/.././C" => "A/C"
"../C" relative to "A/B" => "A/B/../../C" => "C"
Best,
Rawld
Right, sorry, I replied to the first message that had my very bad example.
James
Definitely, if we get agreement on the resolution policy, I will add a
pull request for the amd-tests repo with a valid test.
Looking at the CommonJS Modules 1.1.1 page:
http://wiki.commonjs.org/wiki/Modules/1.1.1
it looks like they also specify in the Module Specifiers section:
"Relative identifiers are resolved relative to the identifier of the
module in which "require" is written and called. "
So for me that is more impetus to go with module ID resolution.
I would like to hear from John Hann to get his current view on it
given that some IOC types of mappings are possible, and stand-alone
microlib mapping work in either case.
James
ben...
I am fine with this. This makes sense, is predictable, seems to
handle many use cases, and is consistent with how I interpret the
arguably loose CommonJS Modules/1.1 spec.
However, I am also contemplating a feature in curl.js that allows Ben
-- as well as my team -- to create pseudo-packages. These look like
top-level packages even if they're really embedded deep in another
package.
Actually, I'm leaning towards removing the whole concept of "path
mappings" and implementing "package mappings" instead. I think
calling them "paths" is misleading if we take the approach we've
agreed to here. I was under the impression that "paths" allowed me to
map anything I wanted: packages, modules, plugins, resources. (Indeed
RequireJS works this way now, as does curl.js.)
What's really funny (to me) is that several of you have been thinking
just the opposite: remove the concept of packages in favor of paths,
IIUC. For example, there was talk to remove the "lib" property of
packages since it's really just a path. If you do this, how does
somebody specify that the A/B module is actually at A/lib/B or A1.6.1/
src/B ?
-- J
To me, this just sounds like the paths mapping is just lower: so
instead of 'foo': 'fooPkg', it is 'foo': 'fooPkg/some/other/dir'. I am
interested in learning more of your approach though.
In the meantime, I'll be changing requirejs to do the relative module
resolution, and I'll work up a test for the amdjs-tests to exercise
that rule.
> Actually, I'm leaning towards removing the whole concept of "path mappings"
> and implementing "package mappings" instead. I think calling them "paths"
> is misleading if we take the approach we've agreed to here. I was under the
> impression that "paths" allowed me to map anything I wanted: packages,
> modules, plugins, resources. (Indeed RequireJS works this way now, as does
> curl.js.)
Those mappings are still related to paths. The relative ID resolution
means that the ID is resolved to the parent ID then the paths mappings
are consulted to generate the final path.
I can see were "paths" could be misleading, maybe "mappings" is a
better one? Although that might cause some confusion with a
package.json idea of "mappings", which can point to zip/tar.gz files.
That said, I could support putting an alias for "paths" to be
"mappings" and then gradually deprecating "paths" in favor of
"mappings" if you want to coordinate on common configuration values.
I'm open to other descriptive names for this functionality.
> What's really funny (to me) is that several of you have been thinking just
> the opposite: remove the concept of packages in favor of paths, IIUC. For
> example, there was talk to remove the "lib" property of packages since it's
> really just a path. If you do this, how does somebody specify that the A/B
> module is actually at A/lib/B or A1.6.1/src/B ?
With requirejs "paths", I would expect a mapping of 'A':
'A1.6.1/src/B' and expect the "main" module to be at A1.6.1/src/B.js.
The packages config seems like too much configuration for very little
payoff, more configuration to burden an app user with. But I'm
interested to know if you see it another way and how it might work.
James
Agree.
>
> In the meantime, I'll be changing requirejs to do the relative module
> resolution, and I'll work up a test for the amdjs-tests to exercise
> that rule.
I will do the same in dojo and bdLoad.
>
> > Actually, I'm leaning towards removing the whole concept of "path
> > mappings" and implementing "package mappings" instead. I think calling
> > them "paths" is misleading if we take the approach we've agreed to here.
> > I was under the impression that "paths" allowed me to map anything I
> > wanted: packages, modules, plugins, resources. (Indeed RequireJS works
> > this way now, as does curl.js.)
>
> Those mappings are still related to paths. The relative ID resolution
> means that the ID is resolved to the parent ID then the paths mappings
> are consulted to generate the final path.
Agree.
>
> I can see were "paths" could be misleading, maybe "mappings" is a
> better one? Although that might cause some confusion with a
> package.json idea of "mappings", which can point to zip/tar.gz files.
> That said, I could support putting an alias for "paths" to be
> "mappings" and then gradually deprecating "paths" in favor of
> "mappings" if you want to coordinate on common configuration values.
> I'm open to other descriptive names for this functionality.
>
> > What's really funny (to me) is that several of you have been thinking
> > just the opposite: remove the concept of packages in favor of paths,
> > IIUC. For example, there was talk to remove the "lib" property of
> > packages since it's really just a path. If you do this, how does
> > somebody specify that the A/B module is actually at A/lib/B or
> > A1.6.1/src/B ?
>
> With requirejs "paths", I would expect a mapping of 'A':
> 'A1.6.1/src/B' and expect the "main" module to be at A1.6.1/src/B.js.
> The packages config seems like too much configuration for very little
> payoff, more configuration to burden an app user with. But I'm
> interested to know if you see it another way and how it might work.
>
I agree with John that there are some other mapping issues. But I'll hold you
all in suspense until I get time to do a good writeup on another thread.
I suggest we keep this thread restricted to "Relative module ID resolution".
And, iiuc, {RequireJS, curl, dojo, bdLoad} are now in agreement.
Best,
Rawld
I have pull request for the amdjs-tests repo that adds an explicit
test for this module resolution:
https://github.com/amdjs/amdjs-tests/pull/1
Unless there are objections or requests for more time to review, I
will likely merge this on Sunday.
James
This came up on the dojo-contributors list, full thread here:
http://thread.gmane.org/gmane.comp.web.dojo.devel/14580but I will summarize and provide some background here for AMD folks
not familiar with path resolution of module IDs.Background
----------------For an AMD loader to work in the browser efficiently, it should only
do one URL lookup for the module. This is different from traditional
CommonJS Modules 1.1 spec loaders on the server, where they normally
use a require.paths array to search for modules.AMD supports the CommonJS type of module IDs that look like
'some/module', which gets mapped to an URL using some configuration in
the loader.This normally involves using a "baseUrl" and appending the module ID
plus '.js' to create the path. So, for 'some/module', the URL ends up
being baseUrl + 'some/module.js'.There are a few AMD implementations, requirejs, curl, bdload/dojo
loader that allow mapping *part* of a module ID to a different path
than what would normally be used if just using the baseUrl.For example, in requirejs, this configuration call would result in an
URL of baseUrl + 'thirdparty/special/some/module.js':require({
paths: {
'some': 'thirdparty/special/some'
}
});Some loaders, like requirejs and dojo, support configuring the
location of a set of modules according to the CommonJS Packages spec's
use of 'main' and 'lib' properties:
http://requirejs.org/docs/api.html#packagesI now believe the 'main' and 'lib' properties of the CommonJS Packages
spec to be bad ideas. Node 0.4 does support the 'main' property.
However Node removed support for 'lib' in 0.4 because of the extra
path magic it required. I agree with this conclusion, as I believe it
contributes to this relative ID problem.Summary of Issue:
----------------If a module does a require('foo') and then foo.js has a
require('./bar'), how should './bar' be resolved to an URL?
Options:
----------------1) "Relative to module ID": resolve the relative module ID, './bar',
relative to the reference ID, 'foo'. So, the relative module ID gets
converted to 'foo/bar' and then the path/package configuration is used
to resolve it.
2) "Relative to module URL": Resolve the relative ID './bar' relative
to the reference ID's URL. So, in the simple case: URL prefix +
'foo.js' + './bar.js' (but of course cleaned up to be a real path).
Problems:
----------------There are many configurations where #1 and #2 result in the same
value, so it does not matter. However, there are two cases where it
makes a difference:1) CommonJS Package's 'lib' directory is in play. In the example, if
'foo' is a CommonJS package, and its main: 'foo.js' and 'lib' is set
to 'scripts', then the paths get resolved to:Option 1: foo/scripts/bar.js
Option 2: foo/bar.jsI suggest we follow Node's lead here and discourage AMD
implementations from implementing 'lib' support. This removes the
problem with this discrepancy, and makes implementation easier all
around.2) paths: configuration. There could be this type of configuration set up:
require({
paths: {
'foo/bar': 'overrides/foo/bar'
}
});The resulting URLs:
Option 1: baseUrl + 'overrides/foo/bar.js'
Option 2: baseUrl + 'foo/bar.js'I believe Option 1 is the desirable behavior, because this allows
proper overriding of modules. This is particularly useful if you are
building a toolkit, and you know that you can deploy a different
version of 'arrayExtras' depending on the deployment scenario (if only
webkit, then map 'arrayExtras' to an empty file). If option 2 is used,
you will *not* be able to override the path used if './arrayExtras' is
used.Summary
----------------Those were the issues I were able to come up with, but I may have
missed something so please point it out. However, based on this
information, I favor using Option 1, 'relative to module ID'.This is actually a change for RequireJS, and I will update the code to
reflect the change if other implementers agree. As part of that
update, I would remove CommonJS Package 'lib' support too.The original reason RequireJS supports Option 2 'relative to module
URL' was because of this issue:
https://github.com/jrburke/requirejs/issues/51but I believe with the removal of 'lib' support issue #51 goes away.
James