On 2013-09-23 19:10, James Burke wrote:
> On Fri, Sep 20, 2013 at 4:23 PM, C Snover <
goo...@zetafleet.com> wrote:
>> 1. The global loader object (`require` or `requirejs` or `curl` or something
>> else) is the only place where several loaders place their configuration
>> mechanisms (though consistently at `loader.config`). Local `require` does
>> not expose the configuration mechanism in most loaders, and the AMD spec
>> says that local `require` is not intended to support passing a configuration
>> object as the first argument. This means that without knowing in advance
>> what the global loader might be it is not possible to reconfigure at runtime
>> from within an AMD module, which Intern needs to be able to do. Since most
>> loaders support the necessary Common Config options, this is an annoying
>> omission that really hinders interoperability.
> The best we came to on this is summarized here:
>
>
https://github.com/amdjs/amdjs-api/wiki/require#local-vs-global-require-
>
> "There is often an implementation-dependent API that will kick off
> module loading; if interoperability with several loaders is needed,
> the global require() should be used to load the top level modules
> instead."
>
> It is up to individual loaders to opt in for that though.
So, AMD loaders that do not expose themselves at `require` can�t be
kicked off or configured without hard-coding an application to know
where else to look for the loader to expose itself.
�well, they can be kicked off in Node.js, because Node.js has a module
system to retrieve the loader module (except for the current release
version of curl).
I don�t know. Having to hard-code this part is just frustrating. It is
normally OK for application authors since they decide which loader they
are using and the entry point is a minor part of an application. Maybe
this is just something too specific to the sort of generic approach that
a testing system like Intern has to take.
Yes. Having to provide support for every AMD loader explicitly like this
is what I am hoping to avoid� but maybe it is impossible.
>> 2. Code executed through `vm.runInThisContext` in Node.js has no reference
>> to a Node.js `require` method, which makes it impossible to load Node.js
>> modules from within the AMD environment. Curl works around this by not using
>> `vm` at all and executing scripts with `eval` (so code has access to the
>> `require` for the `curl` module); RequireJS and Dojo put the require method
>> at `require.nodeRequire` (where `require` is the AMD loader object). In all
>> cases the `require` method is the one from the loader script. Dojo exposes
>> this through the local require; RequireJS does not. RequireJS will attempt
>> to use Node.js `require` automatically to load a module if an AMD load
>> fails; Dojo will not. Being able to reliably access the underlying module
>> system in an identifiable way is important for interoperability on SSJS
>> platforms.
> I am obviously biased and prefer the route requirejs took. I don't
> think local require should have knowledge of node's require, but
> rather local require should just express the need for a module given a
> module ID, and then it is up to the loader to do any bridging with
> Node.
>
> Also, when using an AMD loader, I feel hiding the node require is
> appropriate since it is inferior for network-based front end work, and
> not what the module would see if running in the browser.
>
> Probably good to have other implementers speak to this one though.
The Node.js module loader has behavioural differences versus how AMD
loaders must work by necessity, so trying to transparently call Node.js
through the loader feels wrong to me and I think leads to end-user
confusion. Most pertinently:
1. Node.js walks the filesystem; AMD does not
2. AMD can remap modules; Node.js does not
3. Dependencies in a Node.js module will not resolve the same as
dependencies in an AMD module because of #2, except UMD can sometimes
interfere and then things get extra crazy unless you remove `define`
from scope before trying to use Node�s `require` to load a module
But anyway, the point is that a loader that tries to transparently
bridge the underlying module loader don�t actually follow the rules of
AMD part of the time, which makes the mental model of AMD more complex
than it should be.
(Also, because an AMD loader cannot be effectively modularized without
gross build hackery, and file size is a major consideration, I
personally prefer to make sure that the loader can farm out to loader
plugins as much functionality as possible.)
>> 4. There seems to maybe be some lack of clarity with regards to how
>> `packages` mapping is supposed to work; it looks like maybe RequireJS does
>> not apply packages� `location` if a �module ID� ends in .js, whereas the
>> Dojo loader does? Not 100% sure on this one yet. Still testing.
> Right, module IDs should be IDs, not something that looks like an URL
> or a file name with an extension. Examples of failure cases here where
> the '.js' is useful to put in the module ID would be good to know.
The use case for this is to provide visual differentiation between
loading non-AMD *scripts* and AMD modules using the AMD loader.
Specifically, Intern has an `order` module that does what it sounds like
(makes modules load serially in order). The use signature is
`intern/order!../non-amd-module.js`. Supposing the caller module is at
`foo/tests/non-amd-module`, `foo` is a package defined as `{ name:
'foo', location: 'bar' }`, RequireJS will try to load
`foo/non-amd-module.js` instead of `baseUrl/bar/non-amd-module.js`. Dojo
will load the latter.
This could again probably be worked around with a custom normalize
implementation but it would be nice for normalization to be specified to
work consistently.
Regards,
--
Colin Snover
http://zetafleet.com