Modules: execute deps, modify, execute (was Re: ES Modules: suggestions for improvement)

James Burke jrburke at gmail.com
Wed Jun 27 09:47:01 PDT 2012


On Wed, Jun 27, 2012 at 8:46 AM, Isaac Schlueter <i at izs.me> wrote:
> Re: Conditional Importing
>
> Only allowing `import` at the top level sounds like an ok idea, but
> I'm not so sure it's necessary.  Consider the current require() style:
>
> if (some_rare_condition()) {
>  foo = require('foo')
> }
>
> In requirejs and browserify the 'foo' module will be *defined*, but
> never loaded (ie, prefetched, evaluated for deps, bundled, etc).  In
> Node, it won't be read from the disk or evaluated (but if it's not
> there ON the disk, you'll have problems eventually, which is
> conceptually equivalent to having already been fetched, but without
> the pre-run safety check.)

Clarification for AMD loaders, like requirejs: 'foo' above will be
fully defined in this case. In other words, it and its dependencies
will have been fetched and evaluated *before* the module with that
require('foo') call has been been executed (before its factory
function has been run).

So require('foo') in AMD loaders just gives back the memoized module
value. Conditional dependencies are handled either via callback-style
require:

if(someRareCondition()) {
    require(['foo'], function(foo){});
}

or done via a loader plugin:

var foo = require('has!someRareTestName?foo');

For the browser this makes since because if it is a rare condition,
the code should not even be shipped to the browser, but dynamically
loaded. Of course build tools allow you inline foo if you think you
might need it and do not want a dynamic network call later, and in
that case, then foo is just in the optimized bundle but not
executed/fully defined, until one of those code blocks ask for it.

This "execute dependencies before executing current module" behavior
is the core of the "middle way" I tried to outline on the list
before[1] and is also explained a bit in the most recent blog post[2].

I believe with it, it would allow more of a "run time" system that
still gives enough "compile time" benefit to allow support for:

* "import *" or future things like macros, *without* being a dynamic
scope construct like "with".
* allow easier use of existing js libraries that want to live in the
both the old and new world by doing a runtime registration via a
module API vs syntax.
* since the fully exported value is available before the current
module is executed, it could allow for deeper type checking over what
the "statically check exports properties only" in the current
proposal.

I have prototyped support for "import *" using this approach with the
harmony-hm AMD loader plugin[3], so it is not something purely
theoretical.

The discussion on what is allowed, in particular import *, could still
happen, but at least there would be a baseline that would allow for
them in a way that makes it easier for existing code to transition to
the new world.

More info in the links below, but if it helps I can outline the model
here in a fresh message:

[1] https://mail.mozilla.org/pipermail/es-discuss/2012-April/022098.html
[2] http://tagneto.blogspot.ca/2012/06/es-modules-suggestions-for-improvement.html
[3] https://github.com/jrburke/require-hm

James


More information about the es-discuss mailing list