ben...
I've been arguing that for along time:
http://bdframework.org/bdLoad/docs/bdLoad-tutorial/bdLoad-tutorial.html#nameClashes
and continue to do so:
http://livedocs.dojotoolkit.org/loader/amd#the-amd-api
On Sat, Dec 24, 2011 at 7:23 PM, D. Dotsenko <dvdot...@gmail.com> wrote:
> Claim III - "It CAN be loaded outside of AMD loader. In that scenario
> we want to avoid double loading" - indeed substantially supports the
> need to have named module. Although the module will not be loaded
> twice (since it will be cached by the browser), just, possibly,
> evaled, at most, twice, it's worth a thought. However, same exact
> argument applies to any other JavaScript lib that could be loaded
> outside of AMD, but is AMD-compatible. Do we make them all hard-named?
>
> Actually, we may want jQuery to be evaled second time when it's ran
> through AMD. With the ongoing discussion of "polluting the global
> scope, overriding one version with another" evaling (future) AMD-
> capable (non-polluting) version second time may be the solution, as
> opposed to a perceived problem.
>
> Claim IV - "hard naming the modules will make adoption of AMD pattern
> easier"
> My experience is the opposite. I could not in-line define the modules
> to support simple multiple-versions, failover scenarios. The hard-
> named modules preclude common-sense use of them through common API
> ( define('jquery', ['/path/to/it'], function($){return $}) ) in favor
> of obscure, AMD loader-specific config tricks. Named modules are just
> a pile of pain - definitely do not help in adoption of AMD patterns.
Thanks for naming the claims. I probably have them out of order. Claim
III is actually the main reason for jquery and underscore being named
modules.
Claim III: if jQuery is used an anonymous module definition and it is
loaded in a page with an AMD loader, but *outside* of a loader call,
it will most likely generate an error. This error will occur in the
wild because there are third party scripts that use jQuery, and they
can be loaded on the page, for example as part of a CMS template, that
may not be part of the AMD loading on the page. Yes, this means there
are pages that load two versions of jQuery. It does not matter if we
think that is good practice, it happens.
If an error is generated, that is bad for AMD and bad for jQuery: the
AMD loader will get bug reports and jQuery will likely get them too.
jQuery is more likely to then just pull AMD support than figure it
out, since the problem is really with the AMD loader(s).
To me, it was more valuable to have some sort of AMD support rather
than none, and have it done in a way that does not generate errors.
Since it is *extremely* common to use some other library/jQuery plugin
that depends on jQuery and if that file is using jQuery AMD-style, it
will use the 'jquery' as the dependency name, so (this is Claim I) a
paths mapping will need to be in the project anyway. Or better yet,
use convention of baseUrl + 'jquery.js' to avoid the paths mapping
altogether.
It is true that this makes it harder to use jQuery in a case where you
want to load more than one jQuery in a page, but that is a much
smaller use case than what is described above, and it is best if you
can use tools to help you manage that. If tooling is in play, then
that tooling can help manage named renaming. This is what I plan to do
as part of volo[1].
Now, that is *not* to say that named modules should be encouraged. My
doc with these claims in it explicitly encourages using anonymous
modules. I also do not think anything besides jQuery or underscore
should get this treatment.
End story: upgrading the web is hard. AMD needs to get a foothold to
be seen as useful, and jQuery/underscore support is important in that
goal. Even though it causes problems with multiple AMD versions of
jQuery in an AMD project, and initial project setup, it was worth the
tradeoff.
However, I do think we need to do more evangelizing on how best to set
up AMD projects that avoid configuration (drop jQuery in as baseUrl +
'jquery.js' is the way to go). This is also something I want to push
via volo -- it just does this automatically as part of a library add
-- just drops it in baseUrl as 'jquery.js'.
I probably need to make Claim IV clearer -- it is not about AMD users
having an easier time, but demonstrating for non-AMD code that using
AMD will not break things. In other words, because the issues in Claim
III were avoided, AMD will be viewed as safe to call as part of
libraries that AMD users use.
All that said, here are some things we can do to try to get a handle
on how much of a problem Claim III is:
1) I need to make a test or couple of tests as part of the amd-tests
set that tests what happens when an AMD loader gets a call for an
anonymous module when that anonymous module is not loaded by the AMD
loader.
I am fairly sure that because of the nature of browsers' script onload
notifications that an AMD loader cannot reliably discard the
out-of-loader anonymous define() call, and it will interfere with the
pairing logic that matches anonymous modules to names. However, I
could be mistaken, so having some tests to try it and to investigate
what is going on would help. One of my main goals of RequireJS 1.1 is
this work to try to mitigate this effect, and not throw an error if an
anon module comes in from outside the loader.
It would also be good to get a read from other AMD implementers on
what happens if they get an anon module call outside their
loader-specified scripts. Having the tests would help them test the
issue.
2) For underscore, it could be that it is not used commonly in third
party scripts, not how jQuery is used. I am doubtful, since it is even
a more basic library than jQuery. But I do not have enough experience
with that community to know. If anyone has experience in this area,
that would be helpful.
3) I'm open to rewording the document you got these claims from. Maybe
move Claim III to be the first claim? Maybe pull that whole section
out of that doc and just add a link to that "updating existing
libraries" to just have a link to "why are jQuery and underscore named
libraries?" which then goes to a doc with these claims.
In summary: I want to continue working through this by getting some real data.
[1] https://github.com/volojs/volo
James
<script src="js/libs/curl-0.5.4.min.js"></script>
<script src="js/libs/jquery.js"></script>
<script src="js/loader.js"></script>
Where loader.js contains:
define(
'jquery'
, ['js/libs/jquery']
, function($){
return $
}
)
require(['jquery'], function($) {
...
That second load blows up with:
Error: Multiple anonymous defines found in ./js/libs/jquery.js.
Sounds like something AMD loaders need to fix though, not something
that would compel me to make jquery named module.
Is there really nothing AMD loaders can do to avoid blowing up on
double-load? This same argument can apply to any other js lib
(BigDecimal is on top of list in our case). We can't make them all
named.
Daniel.
> James
Right, this is the difficulty with doing cross browser development but
trying to also develop for the future by just allowing anon modules.
Originally what became the AMD spec did not support anon modules
because we didn't see a way to do it. Fortunately Kris Zyp found a way
to do it. It takes a couple of pathways to support anon modules (of
course IE is different from other browsers).
While we cannot protect against all modules by naming them, once folks
are used to AMD loading, it will be easier to deal with these errors
if they show up for other modules, and we'll likely have some more
tools to help with it too.
But ideally we can make traction in AMD libraries.
I'm hopeful that the actions I do for #1 in my previous list will help
us lock down exactly how much we can mitigate it. I think we might
have a chance to work around the problem, but I will not feel
confident until we have tests and code to prove it out.
It will likely take me a couple of weeks to complete some tests and do
some code inspection for this. However, if you would like to set the
stage by constructing some tests in the meantime, that would be great.
Some tests that would be useful:
1) One similar to what you have now. A basic test.
2) One that does a dynamic, async script load for a script that is
done outside the loader, but while the loader is loading some other
anonymous modules.
I expect the difficulty in the code patch will be handling #2, when
the anonymous define() call happens in the middle of other AMD-loaded
anon script loading. It will also likely take a little bit of tuning
to make sure the test load happens in between files.
James
https://github.com/dvdotsenko/AMDLoaderTests
test1, 2 are passing, these are simple, test scenarios.
test3 is simulating the double load you described. It fails, as you mentioned.
( I used curl.js because it reliably respects require-nesting order
you see in loader.js. With RequireJS i saw in Chrome plugin code fire
before jquery (real one, that one that loads a long time) exec fully.
I don't want to mix the two problems together for this simulation,
hence the use of curl.js)
test3.html is likely what you refer to as scenario (1) below.
Daniel.
(Pushed the patch and note to John Hann.
https://github.com/unscriptable/curl/pull/45)
Ported the tests to RequireJS and, unfortunately see too many things
blowing up. Aside from expected dying on Test3, It was dying on test2.
define(
'baserequirements'
, ['js/libs/jquery.barnacle.js']
, function(){}
)
require(
['jquery', 'baserequirements']
, function($){
$.fn.barnacle()
window.CheckIn("Main Application")
}
)
This is what I saw in log:
/baserequirements.js "Failed to load resource"
Code here, test names start with "rjs_":
https://github.com/dvdotsenko/AMDLoaderTests
I take it there is definitely quite a bit of hacking on AMD-loaders
needed before this "let's make modules anon" issue can be revisited.
Daniel.