Module Loader Comments
On Tue, Mar 12, 2013 at 9:12 AM, Kevin Smith <khs4473 at gmail.com> wrote:
(Referencing harmony:module_loaders)
When creating a custom loader, I believe there ought to be a way to fallback to using the parent loader's fetching behavior from within the fetch hook. After all, you might want to only override the parent loader's fetching behavior for a certain subset of resolved URLs.
The way to invoke the default behavior will be to just return
undefined
from a hook (or fulfill with undefined
for the fetch
hook). We'll be updating the wiki in the next week or two with these
sorts of issues.
If that feature is available, then I think we should consider eliminating the translate hook and instead allow translation semantics to be defined from within the fetch hook.
This won't work, for several reasons:
- It ought to be possible to override the translation behavior without mucking with fetching. Coffeescript translators don't need to perform their own fetching.
- calls to
eval
go through the translate hook, but not through the fetch hook, since there's nothing to fetch.
- Aesthetically, we should keep the module loading kernel as small as possible. Translation is really independent from module loading and we should probably push the concept of translation up to a higher layer if possible.
As simple as possible, but no simpler. Loading is about how to turn a reference to a module into the bytes of a JS program, and translation fits right in there. I'm not sure which other layer you're thinking of.
- The current translate hook only provides URLs as input. This might not be sufficient in some cases to determine the appropriate translation. For example, we might want to use the value of a "Content-Type" HTTP header. In such a scenario, the natural place to define that branching logic would be in the fetch hook, after retrieving the file using (X-Domain) HTTP requests.
Passing along this additional data may well be a good idea. We plan
to make basically all the additional arguments to each hook into an
options object, and this would fit there. Note that it wouldn't be
available always, though -- witness the case of eval
.
The way to invoke the default behavior will be to just return
undefined
from a hook (or fulfill withundefined
for the fetch hook).
That's one way to do it. It doesn't allow the overrider to do any transformation on the result though. If the overrider can explicitly call the default behavior, then source translation could just be done from within the fetch hook.
We'll be updating the wiki in the next week or two with these
sorts of issues.
The sooner the better! Modules are (IMO) the most important new feature of ES6 and it's getting close...
- It ought to be possible to override the translation behavior without
mucking with fetching. Coffeescript translators don't need to perform their own fetching.
First, if the default behavior is explicitly invoked (as opposed to implicitly by returning undefined), then fetching doesn't really have to be mucked with.
Also (and this is a separate point), I don't see how in the current design a CoffeeScript translator could be implemented as a custom loader. As far as I can tell, all loaders encapsulate their own module instance table. For CoffeeScript, you want the JS module instance table and the CS module instance table to be the same. Is there a way to have a custom loader share an instance table with another loader, then?
- calls to
eval
go through the translate hook, but not through the fetch hook, since there's nothing to fetch.
So we're going to have eval execute arbitrary languages other than javascript? I didn't realize this... I'm going to have to think on that for a while.
Thanks for debating, BTW!
On Thu, Mar 14, 2013 at 11:03 AM, Kevin Smith <khs4473 at gmail.com> wrote:
The way to invoke the default behavior will be to just return
undefined
from a hook (or fulfill withundefined
for the fetch hook).That's one way to do it. It doesn't allow the overrider to do any transformation on the result though. If the overrider can explicitly call the default behavior, then source translation could just be done from within the fetch hook.
That's why for several of the hooks, we plan to provide to the hook an
explicit value which is what the default would do. For translate
this isn't needed, since the default is not to transform, and for
fetch
browsers already provide ways of doing remote fetching. I
don't think we want to force engines to reify these operations as new
JS functions.
We'll be updating the wiki in the next week or two with these sorts of issues.
The sooner the better! Modules are (IMO) the most important new feature of ES6 and it's getting close...
Glad you're excited about modules.
- It ought to be possible to override the translation behavior without mucking with fetching. Coffeescript translators don't need to perform their own fetching.
First, if the default behavior is explicitly invoked (as opposed to implicitly by returning undefined), then fetching doesn't really have to be mucked with.
Also (and this is a separate point), I don't see how in the current design a CoffeeScript translator could be implemented as a custom loader. As far as I can tell, all loaders encapsulate their own module instance table. For CoffeeScript, you want the JS module instance table and the CS module instance table to be the same. Is there a way to have a custom loader share an instance table with another loader, then?
For this use case, you'd probably want to just modify the default System loader to understand Coffeescript, via file extension detection, AMD-style plugins, or some other mechanism.
If you want a new loader, you'll have to explicitly share the modules that you want to share. But the point of new loaders is to have the distinct table.
- calls to
eval
go through the translate hook, but not through the fetch hook, since there's nothing to fetch.So we're going to have eval execute arbitrary languages other than javascript? I didn't realize this... I'm going to have to think on that for a while.
For Coffeescript, it's easy to actually translate eval
calls.
The more important reason to handle eval
in a loader is so that if
you're enforcing some invariant on code executed in a specific loader,
you don't want the code to be able to escape that invariant via
eval
.
Thanks for debating, BTW!
Hopefully it doesn't need to be a debate. :)
On 3/14/2013 11:03 AM, Kevin Smith wrote:
Also (and this is a separate point), I don't see how in the current design a CoffeeScript translator could be implemented as a custom loader. As far as I can tell, all loaders encapsulate their own module instance table. For CoffeeScript, you want the JS module instance table and the CS module instance table to be the same. Is there a way to have a custom loader share an instance table with another loader, then?
You can't share the table, but you can manually use loaderOne.set(mrl, loaderTwo.get())
after the translate? (I think this would be closest to
the final evaluation) hook.
On 3/14/2013 12:04 PM, Brandon Benvie wrote:
loaderOne.set(mrl, loaderTwo.get())
Sorry, I meant loaderOne.set(mrl, loaderTwo.get(mrl))
. Assuming their
resolve hooks are the same I guess.
The more important reason to handle
eval
in a loader is so that if you're enforcing some invariant on code executed in a specific loader, you don't want the code to be able to escape that invariant viaeval
.
This makes sense now. The loader has the opportunity to analyze and transform external code, so it should also have the same ability with respect to dynamic code. Maybe this rationale could be captured on the wiki.
So it's really more of a "transform" hook than a "translate" hook. Would naming it "transform" would make the intention more obvious?
On Thu, Mar 14, 2013 at 2:14 PM, Kevin Smith <khs4473 at gmail.com> wrote:
So it's really more of a "transform" hook than a "translate" hook. Would naming it "transform" would make the intention more obvious?
Transformations of languages are translations, so I think that
translate
is clearer. CS -> JS is a translation.
So it's really more of a "transform" hook than a "translate" hook. Would naming it "transform" would make the intention more obvious?
Transformations of languages are translations, so I think that
translate
is clearer. CS -> JS is a translation.
Sure, but to me "translate" implies translation from one programming language to another. But the "loader" concept can be fully expressed without dependence on on the concept of "other languages". "Transform", to me, implies the more generic concept.
Anyway, my questions are cleared up (for now). Can't wait for those wiki updates! ; )
Anyway, my questions are cleared up (for now). Can't wait for those wiki updates! ; )
Ah - one more comment.
The signatures for load
and evalAsync
indicate that they will return
this
, a reference to the loader. These functions are prime candidates
for returning futures (e.g. something with a then
method) in some future
version of ES with standardized promises/futures. Would it be more
future-safe to leave the return values of these methods undefined
for the
present?
That sounds reasonable to me.
(Referencing harmony:module_loaders)
When creating a custom loader, I believe there ought to be a way to fallback to using the parent loader's fetching behavior from within the fetch hook. After all, you might want to only override the parent loader's fetching behavior for a certain subset of resolved URLs.
If that feature is available, then I think we should consider eliminating the translate hook and instead allow translation semantics to be defined from within the fetch hook.
Aesthetically, we should keep the module loading kernel as small as possible. Translation is really independent from module loading and we should probably push the concept of translation up to a higher layer if possible.
The current translate hook only provides URLs as input. This might not be sufficient in some cases to determine the appropriate translation. For example, we might want to use the value of a "Content-Type" HTTP header. In such a scenario, the natural place to define that branching logic would be in the fetch hook, after retrieving the file using (X-Domain) HTTP requests.
Thoughts? I could be missing an obvious counter-argument, of course ; )