Modules, Concatenation, and Better Solutions

David Herman dherman at mozilla.com
Tue Oct 16 14:58:44 PDT 2012


On Oct 15, 2012, at 6:45 AM, Kevin Smith <khs4473 at gmail.com> wrote:

> OK, so:
> 
>     module A {
>       console.log("a");
>       export var x;
>     }
> 
>     console.log("$");
>     import x from A;
> 
> Does this print:

Good question. The way we have it currently specified isn't ideal for concatenation, I think. The code executes eagerly, from top to bottom, but if it encounters an external load, it executes that external module on demand (i.e., on first import). This means that this:

    // a.js
    import b from "b.js";
    console.log("a");
    export let a = "a";

    // b.js
    console.log("b");
    export let b = "b";

    // main.js
    import a from "a.js";
    console.log("main");

prints "b" then "a" then "main", whereas this:

    module a {
        import b from b;
        console.log("a");
        export let a = "a";
    }
    module b {
        console.log("b");
        export let b = "b";
    }
    import a from "a".js";
    console.log("main");

prints "a" then "b" then "main". That's clearly a problem for simple concatenation. On the one hand, the point of eager execution was to make the execution model simple and consistent with corresponding IIFE code. On the other hand, executing external modules by need is good for usually (except in some cases with cyclic dependencies) ensuring that the module you're importing from is fully initialized by the time you import from it.

I see two coherent alternatives:

(a) execute inline modules by need (i.e., on first import) rather than eagerly
(b) execute external modules "transactionally", trying to order them by dependency so that imported modules have fully initialized before the code that depends on them runs

The weird thing about (a) is that code that appears to be straight-line actually executes in somewhat more unpredictable (although deterministic) order. The downside of (b) is that when you have cyclic dependencies, one module won't even be *partly* initialized before the other module starts running. (Although usually, when you have cyclic dependencies, you probably don't want to be evaluating exports from each other in top-level code -- you want all those mutual references to be happening under functions.)

Dave



More information about the es-discuss mailing list