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.

/caridy

> On Aug 20, 2017, at 8:57 AM, kai zhu <kaizhu...@gmail.com> wrote:
> 
> for the forseeable future, the only practical solution i see to these
> frontend performance issues is to avoid using es modules, and revert
> to the simple, old-fashioned method of assigning libraries to the
> window namespace.
> 
>> On 8/20/17, James Browning <thejameserna...@gmail.com> wrote:
>> These are just some ideas I've had for improving es modules based on
>> my experiences with them. The syntax and stuff with them isn't too
>> important, the main point is the problem I'm trying to solve with each
>> of them, feedback and criticism is welcome.
>> 
>> # Dynamic modules
>> 
>> One of the biggest issues I've had with ES modules is not being able
>> to load classic scripts as part of the dependency graph, one of the
>> solutions I've used but am not particularly happy with is having an
>> async loader function e.g.:
>> 
>> ```js
>> function loadScript(url) {
>>    return new Promise(resolve => {
>>        const scriptElem = document.create('script')
>>        scriptElem.src = url
>>        scriptElem.onload = resolve
>>    })
>> }
>> 
>> // some other file
>> 
>> async function computeSpline() {
>>    await loadScript('./mathjs.js')
>>    // use math here
>> }
>> ```
>> 
>> And while this approach works somewhat it's a bit of a pain for a
>> couple reasons:
>> 
>> - If something gains a `script` dependency it necessarily breaks all
>> consumers by becoming asynchronous even if the original operations
>> were synchronous
>> - It's not generic for other types of resources e.g. I can't load an
>> image without creating another loader function or so on
>> 
>> ---
>> 
>> My proposed solution, dynamic (but static) export:
>> 
>> ```js
>> // math.mjs
>> import loadScript from ".../loadScript.js"
>> 
>> loadScript('./math.js').then(_ => {
>>    const math = window.math
>>    delete window.math
>>    export({
>>        math as default
>>    })
>> })
>> ```
>> 
>> This solution is also generic so it can be used for loading any type
>> of resource:
>> 
>> ```
>> // 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
>>            ...
>>    })
>> ```
>> 
>> Now this solution would be nice because it's generic and allows for
>> loading any (even asynchronous) object as part of the module graph and
>> doesn't cause explosions where because one part becomes asynchronous
>> everything becomes asynchronous.
>> 
>> However there is a deficiency in that it can be quite verbose for
>> similar tasks e.g. loading WebAssembly modules which is why I thought
>> of idea 2:
>> 
>> # Module Arguments
>> 
>> Effectively module arguments would allow passing data to a module
>> (statically) during loading e.g.:
>> 
>> ```js
>> // some-file.js
>> import dict from "./dictionary.js" where { lang = "en-US" }
>> 
>> // dictionary.js
>> fetch(`./dictionaries/${ import.arguments.lang }.txt`)
>>    .then(response => response.text())
>>    .then(text => export({
>>        JSON.parse(text) as default
>>    })
>> ```
>> 
>> This solves the previous problem of very similar dynamic modules for
>> similar types by allowing details like that to be passed in as
>> arguments e.g.:
>> 
>> 
>> ```js
>> import math from "./loadScript.mjs" where {
>>    script = './math.js',
>>    globalName = 'math'
>> }
>> ```
>> 
>> # Lazy Export-From
>> 
>> One of the nice things about named exports is you can minimize the
>> amount of mostly similar `import` declarations e.g.:
>> 
>> ```js
>> import map from "./lodash/map.js"
>> import filter from "./lodash/filter.js"
>> import flatMap from "./lodash/flatMap.js"
>> ...
>> 
>> // can become
>> import { map, filter, flatMap, ... } from "./lodash/lodash.js"
>> ```
>> 
>> However it has a major downside of massively increasing the amount of
>> fetch/parse/execute time for all those additional things exported by
>> the combined module.
>> 
>> My idea is to allow modules to declare that parts need to not be
>> fetched parsed or executed if they're not actually imported e.g.:
>> 
>> ```js
>> // my-operators-library.js
>> static export { map } from "./map.js"
>> static export { filter } from "./filter.js"
>> static export { reduce } from "./reduce.js"
>> ```
>> 
>> Effectively all my idea adds is the `static export` (syntax not
>> important) form that effectively says these names should only be
>> resolved if they're actually imported and can be safely ignored if
>> they're not used. This way you get both the benefits of collection
>> modules (easier to `import` and reduces duplication) and the benefits
>> of individual `import`s (lesser loading sizes).
>> 
>> # Summary
>> 
>> Basically the ideas suggested here are to solve these particular
>> problems I've had with ES modules:
>> 
>> - Unable to load classic scripts (and other types of resources
>> statically e.g. conditional modules) as part of the module graph
>> - Unable to specify more specific behavior for a module to prevent
>> duplication
>> - Either have to have lots of almost duplicate import declarations or
>> have to load unnecessary files
>> 
>> The solutions I proposed aimed to keep the constraint that module
>> exports should remain statically parsable which is why `export({ ...
>> })` shares the syntactic form.
>> 
>> I refrained from specifying the semantics of the specific operations
>> as there's details that'd need to be sorted out for all of them if
>> there is any interest whatsoever in implementing them.
>> _______________________________________________
>> es-discuss mailing list
>> es-discuss@mozilla.org
>> https://mail.mozilla.org/listinfo/es-discuss
>> 
> _______________________________________________
> es-discuss mailing list
> es-discuss@mozilla.org
> https://mail.mozilla.org/listinfo/es-discuss
_______________________________________________
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss

Reply via email to