Modules feedback, proposal

David Herman dherman at
Sat Mar 31 18:30:32 PDT 2012

Hi James,

> 1) Multiple mrls for System.load():
> System.load("jquery.js", "underscore.js", function ($, _) {})
> or
> System.load(["jquery.js", "underscore.js"], function ($, _) {})

Makes sense. The former is a bit muckier but more convenient than the latter. I'll play with the alternatives, thanks.

> 2) Default module path resolution
> However it would be good to specify the default
> logic.

We'll have to in the browser context, but we also have to leave the default logic unspecified enough to accommodate the very different constraints in the browser and server contexts. For example, Node searches the filesystem, which is not something we'd do in the browser.

> For the default logic, it would be great to see it be:
> baseUrl + ID + ".js"

Yeah, I've thought about auto-appending ".js". I think you're right that it opens up the possibility to be a little more abstract.

> I like the idea of having a
> simpler "paths" config for that instead of requiring the developer to
> implement a resolver function or worse include a library to set up the
> resolver (might as well just use an AMD loader then :).

I think we may want something like this, but I'm still thinking about it.

> 3) Modules IDs as strings
> This item of feedback is assuming that the way to get better optimized
> code delivery is to "concatenate" module files together. ...
> With that assumption, module IDs should always be strings.

I agree that we should make sure it's easy to refactor between a module being defined out-of-band vs in-band. But I disagree with your conclusion that module definitions must have string names to achieve this. Let me chew on this question for a bit, but I think the simpler mechanism will be loader configuration/installation.

> 4) export call
> However, I still feel some sort of "export call" is needed, or some
> way to export a function as the module value, to give parity with the
> runtime calls:
> System.load('jquery.js', function ($) { });
> It would be awkward to do this:
> System.load('jquery.js', function (something) { var $ = something.$; });

You're forgetting about destructuring:

    System.load('jquery.js', function({$}) { });

In the context of built-in modules for JS, callable modules are more trouble than they're worth. In ES3, they're important because you want to minimize the number of global definitions you create, you often want your main workhorse of a library to be a function, and there's no easy way for clients to destructure. But in ES6, with destructuring and import, and with modules no longer polluting the global scope, the pressures are simply not the same. And the downsides to callable modules are that it complicates the semantic model, interferes with a bunch of other design constraints (like not mixing up the export namespace with the Function.prototype namespace, and with static linking), and closes off future possibilities like parameterized modules.

> 5) Compile time linking
> While the compile time linking may give some kinds of type
> checks/export name checking, it is only one level deep, it does not
> help with this sort of checking:

That's just unfair. What you're saying is that static scope checking doesn't do type checking. Well, of course not! And type checking doesn't prove your programs are bug-free, and compilers don't write your software for you. But they're still useful tools. Static linking provides us with a bunch of possibilities: in the short term, error checking for some of the the most common errors, as well as enabling conveniences like import *. In the longer term, additional compile-time constructs.

And we already have mechanisms for doing dynamic things. JS has objects and functions and those go a long way. You should know, you've built some incredibly powerful software with them! :)

> 7) Object destructuring
> No need to respond to this item, I just want to put my voice behind
> the backwards-ness of:
> let { draw: drawWidget } = widget;

I know it throws people off, but the fact is that with full destructuring, the syntax just isn't symmetric. Imagine you're destructuring a property as an array of three elements:

    let { [foo, bar, baz]: draw } = widget;

That just doesn't make any sense. I'm not even sure if it could be defined unambiguously.

The way to understand destructuring is that the thing to the left of the colon is the label, and the thing to the right is the structured part. When you construct an object, you are creating an object with labelled property names and computed property values; when you deconstruct an object, you are requested the labelled property names and destructuring the structured property value.


More information about the es-discuss mailing list