Questions about Harmony Modules

James Burke jrburke at gmail.com
Fri Apr 1 17:09:45 PDT 2011


I was looking over the harmony proposals around modules[1], module
loaders[2], and the module examples[3], and have some questions. These
questions come from making a module system/loader that works in
today's browsers/Node/Rhino, via AMD[4] and RequireJS[5].

1) Files as modules do not need module wrapper
====================
Just to confirm, if a JS file contains only a module definition, the
module X{} wrapper is not needed? So I could do the following in the
browser:

module JSON = require('http://json.org/modules/json2.js');

and json.js could just look like:

export stringify = ...;
export parse = ...;

Correct?

2) Set module export value
====================

Is it possible to support setting the value of the module to be a
function or some other value? The Node implementation of CommonJS
modules allows setting the exported value via module.exports = and in
the AMD API, "return value".

This is useful because many modules are just one function, for
instance, a constructor function, and having to create a property name
that is the same name as the module is very awkward, particularly
since module names are not fixed:

import (require('PersonV2')).{Person}

vs.

//This should probably be "module"
//instead of "var", but see question #3
var Person = require('PersonV2');

What about the following rule in a module:

"If return is used in the module, then it sets the value of the
module, and export cannot be used. If export is used in the module,
then return cannot be used".

I know that means a possible syntax issue that is not allowed in
traditional scripts: in the module examples wiki page, a module can
just be a file with no module wrapper, and in that case and with the
rule above, there could be a "return" at the top level. However, maybe
that can be allowed if it is a module?

3) Are "module" and "import" needed inside a module?
====================

I can see that "module" may be needed when defining a module, like:

module Math {}

However, inside a module definition, is it possible to get by without
needing "module" and "import". For instance, instead of this:

module foo {
   import Geometry.{draw: drawShape};
   module a = require('a');

   a.bar();
   drawShape();
}

what about using var or let instead of module, and use destructuring
for the import:

module foo {
   var {draw: drawShape} = Geometry;
   var a = require('a');

   a.bar();
   drawShape();
}

Maybe these are allowed, and the examples need to be expanded? But if
they are allowed, then I do not see the need to specify the use of
"module" and "import" inside a module. The only advantage for import
may be "import Geometry.*" but I would rather see a generalized syntax
for doing that for any object, not just a module, something like:

let {} = Geometry;

That is just an example, I am not a syntax expert, I am not proposing
syntax, and that example probably would not work. I am just trying to
demonstrate the general usefulness of "create a local variable for
each property on this object".

The end goal is trying limit the number of new special things in the
language the developer needs to learn for modules. Ideally it would
be: "use 'module' to declare an inline module, then use require('')
inside it to get handles on other modules, and use var/let and
destructuring as you normally would".

4) How to optimize
====================

How can I combine some modules for optimized code delivery? Is that
out of scope? Is the hope that something like resource packages[6]
take hold? There is value in distributing a single file with many
modules, both for web performance and for command line tools: giving
the developer one file to execute on the command-line is better than
having to ship them a directory.

5) Loader plugins
====================

Some of the AMD loaders support loader plugins[7]. This allows an AMD
module to load other types of resources, and a module can treat them
as a dependency. For instance:

   //The 'text' module knows how to load text files,
   //this one loads text for an HTML template
   var template = require('text!templates/one.html');

   //The 'cs' module knows how to load CoffeeScript-formatted
   //modules via XHR, then transforms the
   //CoffeeScript text to regular JavaScript and
   //then executes that code to define the module.
   var Widget = require('cs!Widget');

Would something like this be possible, perhaps via the module loaders
API? It looks like the resolver API may come close, but I am not sure
it is enough. This may be difficult if the module loader wants to
parse all the require() calls fetch those resources before doing any
module evaluation, where loader plugins are modules that implement an
API and need to be evaluated and allow them to process the dependency
string to satisfy the dependency.

6) Loader API: multiple modules
====================

The loader API seems to only allow loading one module at a time with a
callback (looking at Loader.load). Is there a way to say "load these
three modules, and call this callback when all three are loaded"?

7) Cross-domain script loading
====================

Given the modules examples page, it looks like it will be possible to
load scripts from other domains, just confirming that it will be
allowed, particularly in the browser.
--------

I apologize for the long email. If some items need longer discussion,
I'll break them out into separate threads.

[1] http://wiki.ecmascript.org/doku.php?id=harmony:modules
[2] http://wiki.ecmascript.org/doku.php?id=harmony:module_loaders
[3] http://wiki.ecmascript.org/doku.php?id=harmony:modules_examples
[4] http://wiki.commonjs.org/wiki/Modules/AsynchronousDefinition
[5] http://requirejs.org
[6] http://limi.net/articles/resource-packages

James


More information about the es-discuss mailing list