John Barton johnjbarton at
Wed Jul 2 09:09:23 PDT 2014

On Wed, Jul 2, 2014 at 1:09 AM, Jussi Kalliokoski <
jussi.kalliokoski at> wrote:

> On Tue, Jul 1, 2014 at 10:28 PM, Kevin Smith <zenparsing at> wrote:
>>  As such, we are balancing the marginal user experience gains of
>>> "export-overwriting" against the better support for circular dependencies
>>> of "real" modules.
>> Another way of looking at it:
>> Being in control of the language, you can always invent new sugar to
>> optimize user experience (within limits) when real usage data proves its
>> worth.  But the core model can't be changed.
>> As such, it seems like it would be better to err on the side of making
>> the core model simple and solid, leaving minor UX optimizations to future
>> syntax.
> But it's neither simple nor solid. It's overtly complicated to support
> features that shouldn't be there.

Actually I think you have missed important features that the current
proposal supports and are needed for your use cases.

> Sorry in advance for the tone of this message, it is quite negative. But
> the intent is constructive. To me modules are the most anticipated feature
> in ES6 and I've been closely following the discussion and the proposal's
> evolution and I've been extremely thrilled. Finally we could have a chance
> of alleviating the situation of having a ton of non-intercompatible
> different module loaders. I haven't contributed much to the discussion
> since I liked the overall direction. However, now that I've been actually
> using the modules for a while with a couple of different transpilers, it's
> become obvious that the design is inherently broken (not the fault of the
> transpilers, they are actually probably better in some aspects than the
> real thing), and in order for ES modules to help the situation instead of
> making it worse, it needs to be better than the existing solutions.
> The core unique selling points of ES6 modules as opposed to the other
> module loading systems:
> * Language built-in: the strongest point. This makes sure that most
> tooling should support the feature out of the box and that module authors
> are more inclined to provide their modules in this format. But the design
> can be whatever and this point will still hold true, so no points to the
> design here.
> * (Reliably) statically analyzable syntax. This is my favourite feature
> and really awesome. Allows engine to fetch next modules while the current
> one is still being parsed,

This isn't true -- all module designs in play require parsing (include of
course CJS and AMD).

> and tooling to better understand what the code does. However, this would
> hold true even if all we standardized was syntactic sugar on top of
> requirejs.

I don't believe that anyone expects such an outcome.

> * Cyclic dependencies: First of all, this is not a feature you want to
> necessarily encourage. It looks good in academia, but in my career I've yet
> to see real world code that would benefit more from cyclic dependencies
> more than refactoring. Not to mention that having cyclic dependencies have
> been possible in global scope modules since LiveScript, and is possible in
> CommonJS as well if you do a little DI:
> (I had
> such a hard time coming up with an example that could use cyclic
> dependencies that I had to dig the example from modules examples wiki). And
> honestly I don't think it's a feature that deserves to be easier to do than
> my example, and especially not worth making other design compromises for.

The arguments for and against supporting cyclic dependencies seem to be
academic. I'm yet to see any evidence of their importance in practice nor
proof they they are fundamental ... or not.

> * Mutable bindings: This will make a good chapter in a future edition of
> JavaScript: The bad parts, along with being able to redefine undefined. You
> can have mutable bindings in other module systems as well, just reassign
> something in your exports and then your consumer uses the exports property
> directly. A lot of WTFs avoided and even doing it like that will ring alarm
> bells in code review.
> * Compile-time errors: This not a feature, it's a bug. Try finding a
> website that doesn't somewhere in its code check for whether you have a
> feature / module available, i.e. optional dependencies. Some examples:
> Angular has jQuery as an optional dependency; spritesheet generator modules
> for node that have multiple engines as optional dependencies because some
> of them may be native modules that don't compile on all platforms. Also
> things get worse if platform features are implemented as modules. Let's say
> things like localStorage, IndexedDB and friends were provided as modules
> and as a result, things like localforage would either not exist or would be
> infinitely more complex. Just look at github search for keywords `try` and
> `require`
> to see how widely used the pattern of wrapping a module load in a try-catch
> is.

Optional dependency is completely supported by Loader.import().
 Furthermore its promise based API avoids try/catch goop.

> Now let's look at some things that tip the odds into existing solutions
> favor:
> * Massive amount of existing modules.
> * Existing large-scale user-bases.
> * Node has stated that the core will always be CommonJS, meaning that on
> node, in order to use ES6 modules, you'll have to be using two different
> module systems which doesn't sound like a thing that people would do unless
> there's proven benefits.

These points are not relevant since nothing in the current design prevents
these success stories from continuing.

> * Completely dynamic.

Neither Common JS nor AMD modules are not complete dynamic.  Both systems
rely on preprocessing JS to package modules for browsers.

> Now, I know there are people that think that this isn't not good, but it
> is. It gives you a lot of power when debugging things or playing around
> with new things (something I haven't seen discussed re:modules on this
> list). One of the greatest things in JS is that instead of reading the
> usually poor documentation, let alone the code, of something you want to
> use you can just load it up in node or the developer tools and play around
> with it. With node, you require() something in the repl and you see
> immediately what it exports.

Loader.get() provides the module.

> You can do whatever with the exports: enumerate, extend your own exports
> with them, whatever you want, it's just an object.

As far as I understand it, the return value from Loader.get() is also an
object.  The mutable bindings are not mutable after import: they are  just

> In debugging situations and learning of new libraries, it's really
> straightforward to just require the module and give it different inputs to
> see what the outputs to see if it's something you want to use or what's the
> edge case of the method that causes the bug you're trying to fix (and then
> just make a failing test out of it). I can't tell you how many times a day
> I write angular.element(document.body).injector().get("Something") or
> require(function (Something) { window.Something = Something }) in the dev
> tools.

IMO, poor support for modules in devtools is a consequence of delay in the
ES process for modules.

> With the current design of ES6 modules, I don't think it's even feasible
> to allow the users to type into the devtools console first `import
> something from "somewhere"` and then in the next entry refer to
> `something`.

Loader.import() provides this ability.

> Not to mention that the dynamic loading in the existing solutions caters
> for situations like build tools, for example loading grunt tasks. The case
> there is that a lot of grunt plugins have dependencies lists from here to
> the end of the world, so when you run a task, you only want to load the
> modules that are required by that task to avoid concatenating files taking
> 20 seconds because it loads a ton of crap for other tasks. So people
> started loading the modules when the tasks get called, not all at the same
> time when initializing and this proved to have significant performance
> benefits. So much that now there's jit-grunt that by guessing and
> configuration is able to load the modules for a given task when the given
> task is invoked. This is simply not possible with ES6 modules without a
> massive boilerplate spaghetti with async stuff.

Badly designed systems will exist independent of language features. The
combination of statically analyzed declarative imports and dynamic
imperative import allows much better tool support than is possible with
Common JS and AMD.

> Given all this, how are we supposed to convince people to use this stuff?
> These concerns are not something that can be fixed later either, they're
> fundamental to the current design.

I think that you are misunderstanding the current design. I do agree that
devtools support is very important. Sadly this support is not given enough
weight. We warned about the issue with exceptions in Promises and now we
have Promises that easily make programs essentially undebuggable. Modules
are less fundamentally broken, but they have more surface area for tools to

> Now I can guess you're thinking that this was purely destructive, so
> where's the constructive part? The key takeaway is that I'm no longer sure
> that we should even try to ship modules with ES6. On the web platform, it's
> better to not hurry shipping something that's just going to end up on the
> wall of shame of short-sighted decisions. Brendan probably knows this the
> best. :) Let's take the time to actually ship something that we can
> confidently say is better than the status quo rather than doing this:

This commonly cited comic is both true and not a sign of problems: progress
is in fact N+1 standards.  That's they way human interaction works.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <>

More information about the es-discuss mailing list