James Browning (2017-08-21T02:00:09.000Z)
> export values are dynamic today! you can do:

> let lib = null;
> export default lib;
> loadScript("foo").then(o => lib = o);

> but what cannot be dynamic, is the set of export names, which shapes the module.

Cariday, while interesting the main problem with this approach is it
doesn't guarantee that the desired module is actually usable at any
particular point e.g. this might not work:

```js
// math.mjs
let math
export { math as default }
loadScript('./math.js').then(_ => {
    math = window.math
    delete window.math
})

// cardinalSpline
import math from "./math.mjs"

export default function cardinalSpline() {
   // use math to compute the spline here
}

// import that function
import cardinalSpline from "./cardinalSpline.mjs"

// I can't reliably use cardinalSpline here yet as math might still be undefined
// even after asynchronous work I can't reliably use it as the script
// might still be fetching
```

---

Dante, I didn't really clarify what I meant by conditional exports, I
don't mean things that sometime export but sometimes don't, the names
exported should remain static but rather what is exported depends on
(possibly asynchronous) things e.g.:

```js
if (typeof self !== 'undefined') {
    // Browser like
    loadScript('./math.js')
        .then(_ => {
             const math = window.math
             export({ math })
             delete window.math
        })
} else {
    // Try node like
    // we'll ignore other environments for now for simplicity
    export({ require('mathjs') as math })
}
```

I'd expect it to be a syntax error if the exported names in one
`export(...)` were different to any other `export(...)` to preserve
the fixed names.

Concerning the other point modules in the browser are *already* async,
it's just observable that they're async and that's the whole point of
why I want dynamic modules is that they can do asynchronous work
before completion, note that the imported module *is* available
synchronously as the module won't be executed until the export
resolves e.g.:

```js
// math.mjs
loadScript('./math.js').then(_ => {
    const math = window.math
    export({ math })
    delete window.math
})

// other file
import math from "./math.mjs"

// We can reliably use math here as this file will not
// be executed until export({ ... }) is reached
// in my idea export(...) is similar to Promise.resolve
```

Foreign module types is nothing new the spec is [specifically designed
for them](https://tc39.github.io/ecma262/#sec-abstract-module-records),
this is how CommonJS will work with `import commonJS from
"commonJSmodule"`. My idea is simply to add a way to add those dynamic
module types as a part of the language instead of part of the loader.


> By passing arguments in, what do you expect to occur? Do you expect the module itself to be run with those arguments, exporting a set of things? How is that any better than just importing a constructor function from the module/library? This problem sounds like designing the library in a better way would make more sense than affording config to be passed into import, which would mean each import would re-run the module, so no caching.

Yes I'd expect it to evaluate multiple times (but fetch/parse only
once) which saves round trips, I mostly only thought of it because of
the way I suggested how dynamic export could work, without dynamic
export it's not particularly useful, it's mostly for reducing the
amount of those script/wasm -> es module modules.

Admittedly I hadn't really thought module arguments through that much
(would same arguments result in the same module object, etc etc), the
whole idea might be rubbish, but the main problem I was trying to
solve with them was automatic creation of dynamic modules so that you
wouldn't need a module like:

```js
// highPerformanceMath.mjs
fetch('.../math.wasm').then(response => response.arrayBuffer())
    .then(buffer => WebAssembly.instantiate(buffer, {}))
    .then(({ instance }) => {
        export({
            instance.exports as default
        })
        // or potentially named exports
        export({
            instance.exports.fastFourierTransform as fastFourierTransform
            ...
    })

```

for every single WebAssembly module you wanted to import and use
synchronously, although in retrospect you probably would still need to
*anyway* if you want to name the exports as the `export({...})` syntax
is still a static declaration of names (it's not an object you can
just populate with names).

> I can see a benefit for reducing files in the static export -- that suggestion has been a good example of existing problems with tree shaking d3, to which the response has been "design better exports". As for the multiple fetch part of the problem, HTTP/2 spec addresses the performance hit for that, and it's effectively what you're asking the "static" prefix to assert. Out of curiosity, how would you expect static to work in the first place? Who would do the assertion that it doesn't depend on any other symbol in the module it is a part of?

HTTP/2 is orthogonal to the goal of `static export ... from`,
basically HTTP/2 allows for serving all dependencies faster when the
dependency graph is known. My idea of `static export ... from` is
basically built-in tree shaking, if a name isn't imported then that
part of the module graph is simply not fetched/parsed/evaluated for
example:

```js
// Note that my suggestion *only* works with export-from
// it does not work with plain `export` as that is already
// fetched and parsed

// operators.mjs
static export { map } from "./operators/map.js"
static export { filter } from "./operators/filter.js"
static export { reduce } from "./operators/reduce.js"
static export { flatMap } from "./operators/flatMap.js"

// other file
import { map, flatMap } from "./operators.mjs"
// only ./operators/map.js and ./operators/flatMap.js
// will be fetched parsed and executed (assuming no other modules)

// another example
import * as operators from "./operators.mjs"
// we can't reason that some of the things might not be used
// so files are fetched/parsed/evaluated
```

> I feel like out of these, the solution is much closer to "Better library design". I'm still not 100% on how your dynamic example addresses "turns my code async".  Static export is an interesting one -- effectively asking for pure symbols. Maybe identify an entire file as "load only these symbols, ignore other source"?

The problem is while it's easy to design within your own code a good
API, if you include a classic script as part of the dependency graph
currently then that forces things to become async for example this
simple example:

```js
// classic script loaded to access functions
// as math.mjs
export default loadScript('./math.js')
    .then(_ => {
        const math = window.math
        delete window.math
        return math
    })

// cardinalSpline.mjs
import math from "./math.mjs"

// This function is needlessly async, if math.js were an ES module
// this function would easily be synchronous, only the
// fact that I had to load a classic script is this async
async function cardinalSpline(points, divisions) {
    const m = await math
    // compute cardinal spline points here
}
```

The worst part about this is if *any* module needs to load a classic
script it potentially explodes throughout the code base converting
many previously synchronous operations into needlessly asynchronous
ones.

The whole point of my dynamic module idea was so that a classic script
can be added as a dependency which is part of the module graph, but
doesn't cause an explosion where previously synchronous functions
become asynchronous just because of a classic script.

Now I've never actually let the explosion thing happen because instead
of turning all the codebase into async functions for otherwise
synchronous things I tend to just take the code of the library,
convert it to a module myself and then use it. But this is time
costly, converting all these classic scripts (or pulling out parts of
them I need) into ES modules is just cumbersome.

The fact that dynamic modules allow for potentially *any*
fetch/parse/evaluation desired (e.g. WebAssembly, HTML modules,
anything you want really) is just a nice consequence of the problem I
was trying to solve, the fact it allows for so many generic use cases
is why I suggested it should be part of the language itself.

If there's no interest in implementing dynamic modules then I might
just suggest the idea of `import math from "script:./math.js"` as part
of the HTML spec for loading classic scripts as part of the module
graph, but I think dynamic modules would be more powerful and useful.

On 8/21/17, Andrea Giammarchi <andrea.giammarchi at gmail.com> wrote:
> I've solved this (for my needs) long time ago, the pattern is the
> following:
>
> ```js
> export default new Promise(async $export => {
>   // await anything that needs to be imported
>   // await anything that asynchronous
>   // finally export the module resolving the Promise
>   // as object, function, class, ... anything
>   $export(
>     {module: 'object'} ||
>     function () {}     ||
>     class Anything {}
>   );
> });
> ```
>
> You can do pretty much everything you need as both consumer or exporter.
>
> ```js
> // ES2017 Asynchronous Export
> // module.js
> export default new Promise(async $export => {
>   const module = await Promise.resolve(
>     {my: 'module'}
>   );
>   $export(module);
> });
>
> // - - - - - - - - - - - - - - - - - - - - - - - - - - - -
>
> // ES2015 consumer
> import module from './module.js';
>
> module.then(exports => {
>   // will log "module"
>   console.log(exports.my);
> });
>
> // - - - - - - - - - - - - - - - - - - - - - - - - - - - -
>
> // ES2017 consumer
> (async () => {
>   const module = await (
>     await import('./module.js')
>   ).default;
> })();
>
>
> // - - - - - - - - - - - - - - - - - - - - - - - - - - - -
>
> // ES2017 consumer and exporter
> export default new Promise(async $export => {
>   const module = await (
>     await import('./module.js')
>   ).default;
>   $export({module, method(){}});
> });
> ```
>
> The pattern easily inter-operate with CommonJS
>
> ```js
> // CommonJS consumer and/or importer
> module.exports = new Promise(async $export => {
>   const module = await require('./module');
>   $export({module, method(){}});
> });
> ```
>
> I still don't understand why it's difficult to imagine asynchronous exports
> when it's apparently normal to imagine asynchronous imports .... but that's
> another story.
>
> Best Regards
>
>
>
>
>
>
> On Sun, Aug 20, 2017 at 8:35 PM, dante federici
> <c.dante.federici at gmail.com>
> wrote:
>
>>
>>    - Unable to load classic scripts (and other types of resources
>>    statically e.g. conditional modules) as part of the module graph
>>
>> How are conditional imports static? In both examples I see the module as
>> being async, and therefore every dependent module is async. Your "dynamic
>> but static" is explicitly using "then" -- or are you implying a module
>> exporting async resources is a better solution than an async module?
>>
>>
>>    - Unable to specify more specific behavior for a module to prevent
>>    duplication
>>
>> By passing arguments in, what do you expect to occur? Do you expect the
>> module itself to be run with those arguments, exporting a set of things?
>> How is that any better than just importing a constructor function from
>> the
>> module/library? This problem sounds like designing the library in a
>> better
>> way would make more sense than affording config to be passed into import,
>> which would mean each import would re-run the module, so no caching.
>>
>>
>>    - Either have to have lots of almost duplicate import declarations or
>>    have to load unnecessary files
>>
>> I can see a benefit for reducing files in the static export -- that
>> suggestion has been a good example of existing problems with tree shaking
>> d3, to which the response has been "design better exports". As for the
>> multiple fetch part of the problem, HTTP/2 spec addresses the performance
>> hit for that, and it's effectively what you're asking the "static" prefix
>> to assert. Out of curiosity, how would you expect static to work in the
>> first place? Who would do the assertion that it doesn't depend on any
>> other
>> symbol in the module it is a part of?
>>
>> I feel like out of these, the solution is much closer to "Better library
>> design". I'm still not 100% on how your dynamic example addresses "turns
>> my
>> code async".  Static export is an interesting one -- effectively asking
>> for
>> pure symbols. Maybe identify an entire file as "load only these symbols,
>> ignore other source"?
>>
>> _______________________________________________
>> es-discuss mailing list
>> es-discuss at mozilla.org
>> https://mail.mozilla.org/listinfo/es-discuss
>>
>>
>
thejamesernator at gmail.com (2017-08-21T02:28:09.943Z)
> export values are dynamic today! you can do:

> let lib = null;
> export default lib;
> loadScript("foo").then(o => lib = o);

> but what cannot be dynamic, is the set of export names, which shapes the module.

Cariday, while interesting the main problem with this approach is it
doesn't guarantee that the desired module is actually usable at any
particular point e.g. this might not work:

```js
// math.mjs
let math
export { math as default }
loadScript('./math.js').then(_ => {
    math = window.math
    delete window.math
})

// cardinalSpline.mjs
import math from "./math.mjs"

export default function cardinalSpline() {
   // use math to compute the spline here
}

// import that function
import cardinalSpline from "./cardinalSpline.mjs"

// I can't reliably use cardinalSpline here yet as math might still be undefined
// even after asynchronous work I can't reliably use it as the script
// might still be fetching
```

---

Dante, I didn't really clarify what I meant by conditional exports, I
don't mean things that sometime export but sometimes don't, the names
exported should remain static but rather what is exported depends on
(possibly asynchronous) things e.g.:

```js
if (typeof self !== 'undefined') {
    // Browser like
    loadScript('./math.js')
        .then(_ => {
             const math = window.math
             export({ math })
             delete window.math
        })
} else {
    // Try node like
    // we'll ignore other environments for now for simplicity
    export({ require('mathjs') as math })
}
```

I'd expect it to be a syntax error if the exported names in one
`export(...)` were different to any other `export(...)` to preserve
the staticness of names in ES modules.

Concerning the other point modules in the browser are *already* async,
it's just not observable that they're async and that's the whole point of
why I want dynamic modules is that they can do asynchronous work
before completion, note that the imported module *is* available
synchronously as the module won't be executed until the export
resolves e.g.:

```js
// math.mjs
loadScript('./math.js').then(_ => {
    const math = window.math
    export({ math })
    delete window.math
})

// other file
import math from "./math.mjs"

// We can reliably use math here as this file will not
// be executed until export({ ... }) is reached
// in my idea export(...) is similar to Promise's resolve
```

Foreign module types is nothing new the spec is [specifically designed
for them](https://tc39.github.io/ecma262/#sec-abstract-module-records),
this is how CommonJS will work with `import commonJS from
"commonJSmodule"`. My idea is simply to add a way to add those dynamic
module types as a part of the language instead of part of the loader.


> By passing arguments in, what do you expect to occur? Do you expect the module itself to be run with those arguments, exporting a set of things? How is that any better than just importing a constructor function from the module/library? This problem sounds like designing the library in a better way would make more sense than affording config to be passed into import, which would mean each import would re-run the module, so no caching.

Yes I'd expect it to evaluate multiple times (but fetch/parse only
once) which saves round trips, I mostly only thought of it because of
the way I suggested how dynamic export could work, without dynamic
export it's not particularly useful, it's mostly for reducing the
amount of those script/wasm -> es module modules.

Admittedly I hadn't really thought module arguments through that much
(would same arguments result in the same module object, etc etc), the
whole idea might be rubbish, but the main problem I was trying to
solve with them was automatic creation of dynamic modules so that you
wouldn't need a module like:

```js
// highPerformanceMath.mjs
fetch('.../math.wasm').then(response => response.arrayBuffer())
    .then(buffer => WebAssembly.instantiate(buffer, {}))
    .then(({ instance }) => {
        export({
            instance.exports as default
        })
        // or potentially named exports
        export({
            instance.exports.fastFourierTransform as fastFourierTransform
            ...
    })

```

for every single WebAssembly module you wanted to import and use
synchronously, although in retrospect you probably would still need to
*anyway* if you want to name the exports as the `export({...})` syntax
is still a static declaration of names (it's not an object you can
just populate with names).

> I can see a benefit for reducing files in the static export -- that suggestion has been a good example of existing problems with tree shaking d3, to which the response has been "design better exports". As for the multiple fetch part of the problem, HTTP/2 spec addresses the performance hit for that, and it's effectively what you're asking the "static" prefix to assert. Out of curiosity, how would you expect static to work in the first place? Who would do the assertion that it doesn't depend on any other symbol in the module it is a part of?

HTTP/2 is orthogonal to the goal of `static export ... from`,
basically HTTP/2 allows for serving all dependencies faster when the
dependency graph is known. My idea of `static export ... from` is
basically built-in tree shaking, if a name isn't imported then that
part of the module graph is simply not fetched/parsed/evaluated for
example:

```js
// Note that my suggestion *only* works with export-from
// it does not work with plain `export` as that is already
// fetched and parsed

// operators.mjs
static export { map } from "./operators/map.js"
static export { filter } from "./operators/filter.js"
static export { reduce } from "./operators/reduce.js"
static export { flatMap } from "./operators/flatMap.js"

// other file
import { map, flatMap } from "./operators.mjs"
// only ./operators/map.js and ./operators/flatMap.js
// will be fetched parsed and executed (assuming no other modules)

// another example
import * as operators from "./operators.mjs"
// we can't reason that some of the things might not be used
// so files are fetched/parsed/evaluated
```

> I feel like out of these, the solution is much closer to "Better library design". I'm still not 100% on how your dynamic example addresses "turns my code async".  Static export is an interesting one -- effectively asking for pure symbols. Maybe identify an entire file as "load only these symbols, ignore other source"?

The problem is while it's easy to design within your own code a good
API, if you include a classic script as part of the dependency graph
currently then that forces things to become async for example this
simple example:

```js
// classic script loaded to access functions
// as math.mjs
export default loadScript('./math.js')
    .then(_ => {
        const math = window.math
        delete window.math
        return math
    })

// cardinalSpline.mjs
import math from "./math.mjs"

// This function is needlessly async, if math.js were an ES module
// this function would easily be synchronous, only the
// fact that I had to load a classic script is this async
async function cardinalSpline(points, divisions) {
    const m = await math
    // compute cardinal spline points here
}
```

The worst part about this is if *any* module needs to load a classic
script it potentially explodes throughout the code base converting
many previously synchronous operations into needlessly asynchronous
ones.

The whole point of my dynamic module idea was so that a classic script
can be added as a dependency which is part of the module graph, but
doesn't cause an explosion where previously synchronous functions
become asynchronous just because of a classic script.

Now I've never actually let the explosion thing happen because instead
of turning all the codebase into async functions for otherwise
synchronous things I tend to just take the code of the library,
convert it to a module myself and then use it. But this is time
costly, converting all these classic scripts (or pulling out parts of
them I need) into ES modules is just cumbersome.

The fact that dynamic modules allow for potentially *any*
fetch/parse/evaluation desired (e.g. WebAssembly, HTML modules,
anything you want really) is just a nice consequence of the problem I
was trying to solve, the fact it allows for so many generic use cases
is why I suggested it should be part of the language itself.

If there's no interest in implementing dynamic modules then I might
just suggest the idea of `import math from "script:./math.js"` as part
of the HTML spec for loading classic scripts as part of the module
graph, but I think dynamic modules would be more powerful and useful.
thejamesernator at gmail.com (2017-08-21T02:02:33.379Z)
> export values are dynamic today! you can do:

> let lib = null;
> export default lib;
> loadScript("foo").then(o => lib = o);

> but what cannot be dynamic, is the set of export names, which shapes the module.

Cariday, while interesting the main problem with this approach is it
doesn't guarantee that the desired module is actually usable at any
particular point e.g. this might not work:

```js
// math.mjs
let math
export { math as default }
loadScript('./math.js').then(_ => {
    math = window.math
    delete window.math
})

// cardinalSpline.mjs
import math from "./math.mjs"

export default function cardinalSpline() {
   // use math to compute the spline here
}

// import that function
import cardinalSpline from "./cardinalSpline.mjs"

// I can't reliably use cardinalSpline here yet as math might still be undefined
// even after asynchronous work I can't reliably use it as the script
// might still be fetching
```

---

Dante, I didn't really clarify what I meant by conditional exports, I
don't mean things that sometime export but sometimes don't, the names
exported should remain static but rather what is exported depends on
(possibly asynchronous) things e.g.:

```js
if (typeof self !== 'undefined') {
    // Browser like
    loadScript('./math.js')
        .then(_ => {
             const math = window.math
             export({ math })
             delete window.math
        })
} else {
    // Try node like
    // we'll ignore other environments for now for simplicity
    export({ require('mathjs') as math })
}
```

I'd expect it to be a syntax error if the exported names in one
`export(...)` were different to any other `export(...)` to preserve
the staticness of names in ES modules.

Concerning the other point modules in the browser are *already* async,
it's just not observable that they're async and that's the whole point of
why I want dynamic modules is that they can do asynchronous work
before completion, note that the imported module *is* available
synchronously as the module won't be executed until the export
resolves e.g.:

```js
// math.mjs
loadScript('./math.js').then(_ => {
    const math = window.math
    export({ math })
    delete window.math
})

// other file
import math from "./math.mjs"

// We can reliably use math here as this file will not
// be executed until export({ ... }) is reached
// in my idea export(...) is similar to Promise.resolve
```

Foreign module types is nothing new the spec is [specifically designed
for them](https://tc39.github.io/ecma262/#sec-abstract-module-records),
this is how CommonJS will work with `import commonJS from
"commonJSmodule"`. My idea is simply to add a way to add those dynamic
module types as a part of the language instead of part of the loader.


> By passing arguments in, what do you expect to occur? Do you expect the module itself to be run with those arguments, exporting a set of things? How is that any better than just importing a constructor function from the module/library? This problem sounds like designing the library in a better way would make more sense than affording config to be passed into import, which would mean each import would re-run the module, so no caching.

Yes I'd expect it to evaluate multiple times (but fetch/parse only
once) which saves round trips, I mostly only thought of it because of
the way I suggested how dynamic export could work, without dynamic
export it's not particularly useful, it's mostly for reducing the
amount of those script/wasm -> es module modules.

Admittedly I hadn't really thought module arguments through that much
(would same arguments result in the same module object, etc etc), the
whole idea might be rubbish, but the main problem I was trying to
solve with them was automatic creation of dynamic modules so that you
wouldn't need a module like:

```js
// highPerformanceMath.mjs
fetch('.../math.wasm').then(response => response.arrayBuffer())
    .then(buffer => WebAssembly.instantiate(buffer, {}))
    .then(({ instance }) => {
        export({
            instance.exports as default
        })
        // or potentially named exports
        export({
            instance.exports.fastFourierTransform as fastFourierTransform
            ...
    })

```

for every single WebAssembly module you wanted to import and use
synchronously, although in retrospect you probably would still need to
*anyway* if you want to name the exports as the `export({...})` syntax
is still a static declaration of names (it's not an object you can
just populate with names).

> I can see a benefit for reducing files in the static export -- that suggestion has been a good example of existing problems with tree shaking d3, to which the response has been "design better exports". As for the multiple fetch part of the problem, HTTP/2 spec addresses the performance hit for that, and it's effectively what you're asking the "static" prefix to assert. Out of curiosity, how would you expect static to work in the first place? Who would do the assertion that it doesn't depend on any other symbol in the module it is a part of?

HTTP/2 is orthogonal to the goal of `static export ... from`,
basically HTTP/2 allows for serving all dependencies faster when the
dependency graph is known. My idea of `static export ... from` is
basically built-in tree shaking, if a name isn't imported then that
part of the module graph is simply not fetched/parsed/evaluated for
example:

```js
// Note that my suggestion *only* works with export-from
// it does not work with plain `export` as that is already
// fetched and parsed

// operators.mjs
static export { map } from "./operators/map.js"
static export { filter } from "./operators/filter.js"
static export { reduce } from "./operators/reduce.js"
static export { flatMap } from "./operators/flatMap.js"

// other file
import { map, flatMap } from "./operators.mjs"
// only ./operators/map.js and ./operators/flatMap.js
// will be fetched parsed and executed (assuming no other modules)

// another example
import * as operators from "./operators.mjs"
// we can't reason that some of the things might not be used
// so files are fetched/parsed/evaluated
```

> I feel like out of these, the solution is much closer to "Better library design". I'm still not 100% on how your dynamic example addresses "turns my code async".  Static export is an interesting one -- effectively asking for pure symbols. Maybe identify an entire file as "load only these symbols, ignore other source"?

The problem is while it's easy to design within your own code a good
API, if you include a classic script as part of the dependency graph
currently then that forces things to become async for example this
simple example:

```js
// classic script loaded to access functions
// as math.mjs
export default loadScript('./math.js')
    .then(_ => {
        const math = window.math
        delete window.math
        return math
    })

// cardinalSpline.mjs
import math from "./math.mjs"

// This function is needlessly async, if math.js were an ES module
// this function would easily be synchronous, only the
// fact that I had to load a classic script is this async
async function cardinalSpline(points, divisions) {
    const m = await math
    // compute cardinal spline points here
}
```

The worst part about this is if *any* module needs to load a classic
script it potentially explodes throughout the code base converting
many previously synchronous operations into needlessly asynchronous
ones.

The whole point of my dynamic module idea was so that a classic script
can be added as a dependency which is part of the module graph, but
doesn't cause an explosion where previously synchronous functions
become asynchronous just because of a classic script.

Now I've never actually let the explosion thing happen because instead
of turning all the codebase into async functions for otherwise
synchronous things I tend to just take the code of the library,
convert it to a module myself and then use it. But this is time
costly, converting all these classic scripts (or pulling out parts of
them I need) into ES modules is just cumbersome.

The fact that dynamic modules allow for potentially *any*
fetch/parse/evaluation desired (e.g. WebAssembly, HTML modules,
anything you want really) is just a nice consequence of the problem I
was trying to solve, the fact it allows for so many generic use cases
is why I suggested it should be part of the language itself.

If there's no interest in implementing dynamic modules then I might
just suggest the idea of `import math from "script:./math.js"` as part
of the HTML spec for loading classic scripts as part of the module
graph, but I think dynamic modules would be more powerful and useful.
thejamesernator at gmail.com (2017-08-21T02:01:51.285Z)
> export values are dynamic today! you can do:

> let lib = null;
> export default lib;
> loadScript("foo").then(o => lib = o);

> but what cannot be dynamic, is the set of export names, which shapes the module.

Cariday, while interesting the main problem with this approach is it
doesn't guarantee that the desired module is actually usable at any
particular point e.g. this might not work:

```js
// math.mjs
let math
export { math as default }
loadScript('./math.js').then(_ => {
    math = window.math
    delete window.math
})

// cardinalSpline.mjs
import math from "./math.mjs"

export default function cardinalSpline() {
   // use math to compute the spline here
}

// import that function
import cardinalSpline from "./cardinalSpline.mjs"

// I can't reliably use cardinalSpline here yet as math might still be undefined
// even after asynchronous work I can't reliably use it as the script
// might still be fetching
```

---

Dante, I didn't really clarify what I meant by conditional exports, I
don't mean things that sometime export but sometimes don't, the names
exported should remain static but rather what is exported depends on
(possibly asynchronous) things e.g.:

```js
if (typeof self !== 'undefined') {
    // Browser like
    loadScript('./math.js')
        .then(_ => {
             const math = window.math
             export({ math })
             delete window.math
        })
} else {
    // Try node like
    // we'll ignore other environments for now for simplicity
    export({ require('mathjs') as math })
}
```

I'd expect it to be a syntax error if the exported names in one
`export(...)` were different to any other `export(...)` to preserve
the staticness of names in ES modules.

Concerning the other point modules in the browser are *already* async,
it's just observable that they're async and that's the whole point of
why I want dynamic modules is that they can do asynchronous work
before completion, note that the imported module *is* available
synchronously as the module won't be executed until the export
resolves e.g.:

```js
// math.mjs
loadScript('./math.js').then(_ => {
    const math = window.math
    export({ math })
    delete window.math
})

// other file
import math from "./math.mjs"

// We can reliably use math here as this file will not
// be executed until export({ ... }) is reached
// in my idea export(...) is similar to Promise.resolve
```

Foreign module types is nothing new the spec is [specifically designed
for them](https://tc39.github.io/ecma262/#sec-abstract-module-records),
this is how CommonJS will work with `import commonJS from
"commonJSmodule"`. My idea is simply to add a way to add those dynamic
module types as a part of the language instead of part of the loader.


> By passing arguments in, what do you expect to occur? Do you expect the module itself to be run with those arguments, exporting a set of things? How is that any better than just importing a constructor function from the module/library? This problem sounds like designing the library in a better way would make more sense than affording config to be passed into import, which would mean each import would re-run the module, so no caching.

Yes I'd expect it to evaluate multiple times (but fetch/parse only
once) which saves round trips, I mostly only thought of it because of
the way I suggested how dynamic export could work, without dynamic
export it's not particularly useful, it's mostly for reducing the
amount of those script/wasm -> es module modules.

Admittedly I hadn't really thought module arguments through that much
(would same arguments result in the same module object, etc etc), the
whole idea might be rubbish, but the main problem I was trying to
solve with them was automatic creation of dynamic modules so that you
wouldn't need a module like:

```js
// highPerformanceMath.mjs
fetch('.../math.wasm').then(response => response.arrayBuffer())
    .then(buffer => WebAssembly.instantiate(buffer, {}))
    .then(({ instance }) => {
        export({
            instance.exports as default
        })
        // or potentially named exports
        export({
            instance.exports.fastFourierTransform as fastFourierTransform
            ...
    })

```

for every single WebAssembly module you wanted to import and use
synchronously, although in retrospect you probably would still need to
*anyway* if you want to name the exports as the `export({...})` syntax
is still a static declaration of names (it's not an object you can
just populate with names).

> I can see a benefit for reducing files in the static export -- that suggestion has been a good example of existing problems with tree shaking d3, to which the response has been "design better exports". As for the multiple fetch part of the problem, HTTP/2 spec addresses the performance hit for that, and it's effectively what you're asking the "static" prefix to assert. Out of curiosity, how would you expect static to work in the first place? Who would do the assertion that it doesn't depend on any other symbol in the module it is a part of?

HTTP/2 is orthogonal to the goal of `static export ... from`,
basically HTTP/2 allows for serving all dependencies faster when the
dependency graph is known. My idea of `static export ... from` is
basically built-in tree shaking, if a name isn't imported then that
part of the module graph is simply not fetched/parsed/evaluated for
example:

```js
// Note that my suggestion *only* works with export-from
// it does not work with plain `export` as that is already
// fetched and parsed

// operators.mjs
static export { map } from "./operators/map.js"
static export { filter } from "./operators/filter.js"
static export { reduce } from "./operators/reduce.js"
static export { flatMap } from "./operators/flatMap.js"

// other file
import { map, flatMap } from "./operators.mjs"
// only ./operators/map.js and ./operators/flatMap.js
// will be fetched parsed and executed (assuming no other modules)

// another example
import * as operators from "./operators.mjs"
// we can't reason that some of the things might not be used
// so files are fetched/parsed/evaluated
```

> I feel like out of these, the solution is much closer to "Better library design". I'm still not 100% on how your dynamic example addresses "turns my code async".  Static export is an interesting one -- effectively asking for pure symbols. Maybe identify an entire file as "load only these symbols, ignore other source"?

The problem is while it's easy to design within your own code a good
API, if you include a classic script as part of the dependency graph
currently then that forces things to become async for example this
simple example:

```js
// classic script loaded to access functions
// as math.mjs
export default loadScript('./math.js')
    .then(_ => {
        const math = window.math
        delete window.math
        return math
    })

// cardinalSpline.mjs
import math from "./math.mjs"

// This function is needlessly async, if math.js were an ES module
// this function would easily be synchronous, only the
// fact that I had to load a classic script is this async
async function cardinalSpline(points, divisions) {
    const m = await math
    // compute cardinal spline points here
}
```

The worst part about this is if *any* module needs to load a classic
script it potentially explodes throughout the code base converting
many previously synchronous operations into needlessly asynchronous
ones.

The whole point of my dynamic module idea was so that a classic script
can be added as a dependency which is part of the module graph, but
doesn't cause an explosion where previously synchronous functions
become asynchronous just because of a classic script.

Now I've never actually let the explosion thing happen because instead
of turning all the codebase into async functions for otherwise
synchronous things I tend to just take the code of the library,
convert it to a module myself and then use it. But this is time
costly, converting all these classic scripts (or pulling out parts of
them I need) into ES modules is just cumbersome.

The fact that dynamic modules allow for potentially *any*
fetch/parse/evaluation desired (e.g. WebAssembly, HTML modules,
anything you want really) is just a nice consequence of the problem I
was trying to solve, the fact it allows for so many generic use cases
is why I suggested it should be part of the language itself.

If there's no interest in implementing dynamic modules then I might
just suggest the idea of `import math from "script:./math.js"` as part
of the HTML spec for loading classic scripts as part of the module
graph, but I think dynamic modules would be more powerful and useful.
thejamesernator at gmail.com (2017-08-21T02:01:10.886Z)
> export values are dynamic today! you can do:

> let lib = null;
> export default lib;
> loadScript("foo").then(o => lib = o);

> but what cannot be dynamic, is the set of export names, which shapes the module.

Cariday, while interesting the main problem with this approach is it
doesn't guarantee that the desired module is actually usable at any
particular point e.g. this might not work:

```js
// math.mjs
let math
export { math as default }
loadScript('./math.js').then(_ => {
    math = window.math
    delete window.math
})

// cardinalSpline.mjs
import math from "./math.mjs"

export default function cardinalSpline() {
   // use math to compute the spline here
}

// import that function
import cardinalSpline from "./cardinalSpline.mjs"

// I can't reliably use cardinalSpline here yet as math might still be undefined
// even after asynchronous work I can't reliably use it as the script
// might still be fetching
```

---

Dante, I didn't really clarify what I meant by conditional exports, I
don't mean things that sometime export but sometimes don't, the names
exported should remain static but rather what is exported depends on
(possibly asynchronous) things e.g.:

```js
if (typeof self !== 'undefined') {
    // Browser like
    loadScript('./math.js')
        .then(_ => {
             const math = window.math
             export({ math })
             delete window.math
        })
} else {
    // Try node like
    // we'll ignore other environments for now for simplicity
    export({ require('mathjs') as math })
}
```

I'd expect it to be a syntax error if the exported names in one
`export(...)` were different to any other `export(...)` to preserve
the fixed names.

Concerning the other point modules in the browser are *already* async,
it's just observable that they're async and that's the whole point of
why I want dynamic modules is that they can do asynchronous work
before completion, note that the imported module *is* available
synchronously as the module won't be executed until the export
resolves e.g.:

```js
// math.mjs
loadScript('./math.js').then(_ => {
    const math = window.math
    export({ math })
    delete window.math
})

// other file
import math from "./math.mjs"

// We can reliably use math here as this file will not
// be executed until export({ ... }) is reached
// in my idea export(...) is similar to Promise.resolve
```

Foreign module types is nothing new the spec is [specifically designed
for them](https://tc39.github.io/ecma262/#sec-abstract-module-records),
this is how CommonJS will work with `import commonJS from
"commonJSmodule"`. My idea is simply to add a way to add those dynamic
module types as a part of the language instead of part of the loader.


> By passing arguments in, what do you expect to occur? Do you expect the module itself to be run with those arguments, exporting a set of things? How is that any better than just importing a constructor function from the module/library? This problem sounds like designing the library in a better way would make more sense than affording config to be passed into import, which would mean each import would re-run the module, so no caching.

Yes I'd expect it to evaluate multiple times (but fetch/parse only
once) which saves round trips, I mostly only thought of it because of
the way I suggested how dynamic export could work, without dynamic
export it's not particularly useful, it's mostly for reducing the
amount of those script/wasm -> es module modules.

Admittedly I hadn't really thought module arguments through that much
(would same arguments result in the same module object, etc etc), the
whole idea might be rubbish, but the main problem I was trying to
solve with them was automatic creation of dynamic modules so that you
wouldn't need a module like:

```js
// highPerformanceMath.mjs
fetch('.../math.wasm').then(response => response.arrayBuffer())
    .then(buffer => WebAssembly.instantiate(buffer, {}))
    .then(({ instance }) => {
        export({
            instance.exports as default
        })
        // or potentially named exports
        export({
            instance.exports.fastFourierTransform as fastFourierTransform
            ...
    })

```

for every single WebAssembly module you wanted to import and use
synchronously, although in retrospect you probably would still need to
*anyway* if you want to name the exports as the `export({...})` syntax
is still a static declaration of names (it's not an object you can
just populate with names).

> I can see a benefit for reducing files in the static export -- that suggestion has been a good example of existing problems with tree shaking d3, to which the response has been "design better exports". As for the multiple fetch part of the problem, HTTP/2 spec addresses the performance hit for that, and it's effectively what you're asking the "static" prefix to assert. Out of curiosity, how would you expect static to work in the first place? Who would do the assertion that it doesn't depend on any other symbol in the module it is a part of?

HTTP/2 is orthogonal to the goal of `static export ... from`,
basically HTTP/2 allows for serving all dependencies faster when the
dependency graph is known. My idea of `static export ... from` is
basically built-in tree shaking, if a name isn't imported then that
part of the module graph is simply not fetched/parsed/evaluated for
example:

```js
// Note that my suggestion *only* works with export-from
// it does not work with plain `export` as that is already
// fetched and parsed

// operators.mjs
static export { map } from "./operators/map.js"
static export { filter } from "./operators/filter.js"
static export { reduce } from "./operators/reduce.js"
static export { flatMap } from "./operators/flatMap.js"

// other file
import { map, flatMap } from "./operators.mjs"
// only ./operators/map.js and ./operators/flatMap.js
// will be fetched parsed and executed (assuming no other modules)

// another example
import * as operators from "./operators.mjs"
// we can't reason that some of the things might not be used
// so files are fetched/parsed/evaluated
```

> I feel like out of these, the solution is much closer to "Better library design". I'm still not 100% on how your dynamic example addresses "turns my code async".  Static export is an interesting one -- effectively asking for pure symbols. Maybe identify an entire file as "load only these symbols, ignore other source"?

The problem is while it's easy to design within your own code a good
API, if you include a classic script as part of the dependency graph
currently then that forces things to become async for example this
simple example:

```js
// classic script loaded to access functions
// as math.mjs
export default loadScript('./math.js')
    .then(_ => {
        const math = window.math
        delete window.math
        return math
    })

// cardinalSpline.mjs
import math from "./math.mjs"

// This function is needlessly async, if math.js were an ES module
// this function would easily be synchronous, only the
// fact that I had to load a classic script is this async
async function cardinalSpline(points, divisions) {
    const m = await math
    // compute cardinal spline points here
}
```

The worst part about this is if *any* module needs to load a classic
script it potentially explodes throughout the code base converting
many previously synchronous operations into needlessly asynchronous
ones.

The whole point of my dynamic module idea was so that a classic script
can be added as a dependency which is part of the module graph, but
doesn't cause an explosion where previously synchronous functions
become asynchronous just because of a classic script.

Now I've never actually let the explosion thing happen because instead
of turning all the codebase into async functions for otherwise
synchronous things I tend to just take the code of the library,
convert it to a module myself and then use it. But this is time
costly, converting all these classic scripts (or pulling out parts of
them I need) into ES modules is just cumbersome.

The fact that dynamic modules allow for potentially *any*
fetch/parse/evaluation desired (e.g. WebAssembly, HTML modules,
anything you want really) is just a nice consequence of the problem I
was trying to solve, the fact it allows for so many generic use cases
is why I suggested it should be part of the language itself.

If there's no interest in implementing dynamic modules then I might
just suggest the idea of `import math from "script:./math.js"` as part
of the HTML spec for loading classic scripts as part of the module
graph, but I think dynamic modules would be more powerful and useful.