Modules feedback, proposal

James Burke jrburke at gmail.com
Sat Mar 31 11:11:50 PDT 2012


On Sat, Mar 31, 2012 at 8:54 AM, Sebastian Markbåge
<sebastian at calyptus.eu> wrote:
> Hi James,
>
> I'd like to add some counter points.
>
> -----------
> 1) Multiple mrls for System.load():
> -----------
>
> I think it makes sense to have this convenience, even though it's probably
> better practice to use the static syntax as much as possible. For
> performance and tooling support. There's some precedence in Web Workers.

In Dave's post:
http://calculist.org/blog/2012/03/29/synchronous-module-loading-in-es6/

the only way to use modules in inline script tags will be via
System.load(), no static syntax allowed. For simple test pages, like
jsbins/jsfiddles, the developer will need a way to pull in a few
scripts at once via System.load. Nested calls would be ugly.

> -----------
> 2) Default module path resolution
> -----------
>
> There should be a way to define completely custom URL resolution for a
> specific loader, yes. The resolver could add a "canonicalize" method that
> can resolve a path relatively to the current file.
>
> I don't think it makes sense for ECMAScript to define the default scheme at
> all. That should be up to the host environment. The browser environment
> should default to the same resolution algorithm as script tags or
> importScripts in Web Workers.

The problem is that with ES.next, scripts are using a JS API to
specify dependencies. This is something new. The existing script
tags/importScripts relies on the developer to properly sequence the
order of the tags.

When Backbone and my app script want to use "jquery" there needs to be
a way to resolve that to the same resource. It seems awkward if
Backbone uses "jquery.js" which by default would map directly to local
disk instead of the CDN.

But say this is what is encouraged: "jquery.js" and the developer is
told to use the resolve API on the Module Loader to map always map
"jquery.js" to the CDN location.

The resolve API is a function. This means the developer has to code up
logic to do if tests on MRL names to see if it should switch the
resolution to a CDN URL.

That if() test will be brittle/wordy to always manually code, so the
developer will code a "helper lib" that allows them to pass a config
object that is used by the helper lib.

Now they have a script loader library dependency. More below.

> For more complex schemes that require configuration, you cannot statically
> resolve the configuration (unless you add the complexity of static
> configuration as well). Therefore you have to use the dynamic loader. Then
> you already have the option to override the resolution scheme when you call
> the loader.
>
>
> Trying to standardize a more complex default scheme is likely to open up a
> lot of bike shedding.

There does not need to be a bikeshed. There is already an existing
scheme that is not complex used by AMD module loaders (baseUrl and
paths config), and it meshes well with other envs like Node, which had
implemented the equivalent of its own resolve logic.

The alternative is to say "we don't want to try to figure it out" will
mean that "config libraries" pop up for doing declarative config,
because that is mostly what is needed.

So now to use modules, I need to include what is the equivalent of a
module loader script. This looks like no net improvement for the end
developer who has to use a module loader today -- they still need to
manage and load script that needs to be called before the rest of
their modules are run.

That loader script that sets the resolve logic will then need to
expose an API that accepts a list of modules to load, since the
configuration needs to be set before the rest of the loading occurs.

It starts to just look like requirejs then. I want script/module
loaders like requirejs to go away. The "just use URLs" approach is not
enough to do that.

> -----------
> 5) Compile time linking
> -----------
>
> Yea, it's true it's just one level. Ultimately you'd hope that engine and
> tool implementors can dynamically link any property reference to frozen
> objects. At least this one level certainly makes it easier to predict this
> behavior for that single level.

The unfortunate thing is that it is a very shallow level, see
jQuery-type APIs or constructor functions. All the action happens that
second level down. Ideally whatever solution could be found for that
second level could also apply to that top level module. I definitely
want to have that kind of checking generically though.

The compile time module linking is not enough, and it makes other
higher value features harder or impossible.

> -----------
> 6) Import syntax
> -----------
>
> Obviously I certainly don't agree that Node and AMD users have done just
> fine without having *. That's one of the reasons I created Labeled
> Modules. https://github.com/labeledmodules/labeled-modules-spec/wiki

We should try for the equivalent of import *, sorry if I was too short
on this point. I'll expand what I meant:

I think it should be a runtime-like thing (probably using the wrong
word there), and just allow it for any object via destructuring:

let {*} from "Math";
let {*} from shape;

However, I'm OK dismissing * if it meant:
1) This * logic is only possible for compile time linking of modules.
2) and that compile time module linking prevents current libs from
doing a runtime opt-in to ES.next modules.

To me #2 is an order of magnitude more important than the compile time
features. If libraries do not have a way to opt in to both the old
world and the new module world, it will make it harder to accept
ES.next.

However, maybe I'm wrong on that. It would be good to hear arguments
on how I misread that or how that transition can be managed well.

> -----------
> 8) Export syntax
> -----------
> I'd like to propose that we need an alternate way to export variables that's
> compatible with ES.old. Otherwise we'll have an unnecessary split between
> ES.old and ES.next when it could be perceived as a single language.

This is my primary concern. I want a way to specify dependencies and
exports that works with ES.old, and ES.next. I believe the
compile-time linking is the thing preventing that, but maybe I am
wrong.

> I like the label approach. It couldn't break existing code and still allow
> for static exports.

Labeled modules do not allow exporting a function as the module value.
I believe it will be very difficult to sell that to the Node and AMD
communities.

Labeled modules also do not allow creating a local name for the
imported dependency, and *always* does the equivalent of an import *.
It seems very hard to match up the right module property to use if you
have two dependencies specified.

James


More information about the es-discuss mailing list