Modules vs Scripts

# John Barton (11 years ago)

Just a user-experience report with traceur: the following code fails to compile in the repl.html and command line compiler:

import {WrapNewObjectTransformer} from './WrapNewObjectTransformer';

export function transcode(src, url) {
    var file = new SourceFile(url, src);
    var reporter = new ErrorReporter();
    var tree = new Parser(reporter, file).parseProgram(true);
    return (new WrapNewObjectTransformer()).transformAny(tree);
}

It fails on 'unexpected token export'. This was unexpected by me ;-)

However it does seem consistent with the grammar in harmony:modules. The |export| keyword is part of an ExportDeclaration which appears in a ModuleElement but not in a ScriptElement. The parser believes it is parsing a Script. So the only way to legally parse JS as a Module is as a side-effect of module loading?

I suppose that a Script is intended to be the root of the dependency tree, so the error message is trying to tell me "You are compiling an interior node of the dependency tree silly". But both Script and Module are things that JS devs will want to compile. Concretely I will want to be able to copy the contents of a JS file and paste it into a repl window to analyze it without having it die on syntax errors because it is a module.

# John Barton (11 years ago)

Could someone help me understand why two goals for parsing JS is a good thing?

# David Herman (11 years ago)

On Nov 16, 2013, at 3:32 AM, John Barton <johnjbarton at google.com> wrote:

Could someone help me understand why two goals for parsing JS is a good thing?

Hm, it sounds like you've assumed a conclusion already. Let me try to explain anyway.

Scripts are for synchronous loading and evaluation; modules are for asynchronous loading and evaluation. The former is not allowed to import, which triggers I/O. The latter is allowed to import. There was always going to have to be a syntactic split.

But there's more. I'll be explaining at this week's TC39 meeting some more details about the intended model for browser integration. In short, declarative code based on modules will use the <module> tag (or <script type="module">, which will mean the same thing and allows polyfilling today). This is better than <script async>, which was a hopeless idea. This also works beautifully for fulfilling the promise of 1JS: a new, better initial environment in which to run top-level application code without requiring versioning.

<module>
  var x = 12;             // local to this module, not exported on global object
  import $ from "jquery"; // asynchronous dependency, NBD
  '$' in this             // nope, because all globals are scoped to this module
  let y = 13;             // yep, let works great because modules are strict
</module>

Same number of characters as <script>, better semantics, better global environment, better language.

If you're not excited about ES6 yet, get excited. :)

# Matthew Robb (11 years ago)

Does this imply <module src=""> ?

# David Herman (11 years ago)

Works either way, inline or external. (Requiring src="" is one of the reasons why <script async> was a non-starter.)

# Brendan Eich (11 years ago)

<3 this, it matches my go-back-to-1995 dreams.

# Matthew Robb (11 years ago)

I like it. If there is a desire to stay closer to <script> I could see <script module> and <script module="">

# Axel Rauschmayer (11 years ago)

Works either way, inline or external. (Requiring src="" is one of the reasons why <script async> was a non-starter.)

Is the value of src a module ID or a path? How about when packages are used (for bundling)? Is there a way to combine module IDs and packages?

# David Herman (11 years ago)

On Nov 17, 2013, at 11:59 AM, Axel Rauschmayer <axel at rauschma.de> wrote:

Is the value of src a module ID or a path? How about when packages are used (for bundling)? Is there a way to combine module IDs and packages?

For the most part the answer to these kinds of questions is that we support "all of the above," but I'd like to wait just a little bit longer before getting into details. Right now we've been focusing on providing a complete base (reflective) layer via the Loader API, which is what will be in ECMA-262; the rest is an HTML spec. (We are thinking through what pieces are necessary for the <module> tag to ensure we haven't missed anything in the Loader API.) I'm focused on getting ES6 out the door, but the next step after that is to start fleshing out the <module> spec.

# Axel Rauschmayer (11 years ago)

That makes sense. So, for starters, I’m guessing one will set up the module loader via a <script> tag (e.g. to enable bundling).

Afterwards, the <module> tag will be used to load modules, via module IDs. Then “src” probably isn’t a good attribute name, “id” isn’t either (clashes with DOM terminology). “from” and “import” seem likely candidates. (Just for the sake of an initial rough story; I do understand that it doesn’t make sense to discuss details, yet.)

# Anne van Kesteren (11 years ago)

On Sun, Nov 17, 2013 at 2:23 PM, Matthew Robb <matthewwrobb at gmail.com> wrote:

I like it. If there is a desire to stay closer to <script> I could see <script module> and <script module="">

Has to be <script type=module> otherwise it would execute in legacy clients.

# Brian Di Palma (11 years ago)

Correct me if I'm wrong David but module import/exports are not dynamic which allows tooling/IDEs to be more intelligent and programmers to easily understand what dependencies a module has/provides?

# Sam Tobin-Hochstadt (11 years ago)

Yes, that's correct, if I guess correctly at what you mean by dynamic.

# Brian Di Palma (11 years ago)

You can statically analyze the module text and enumerate the complete imports and exports of the module without having to execute the module. The execution of the module will not dynamically increase it's imports/exports.

For instance could you have a Math.random that decides if a dependency is required?

# Sam Tobin-Hochstadt (11 years ago)

Yes, exactly.

Of course, running a module can load other modules using the Loaders API, but that doesn't add any new imports or exports to the module itself.