James Browning (2018-03-05T10:50:12.000Z)
thejamesernator at gmail.com (2018-03-05T10:52:13.592Z)
Just as a follow up to these ideas, the first proposal I suggested can be *entirely* resolved with the top level await proposal: https://github.com/MylesBorins/proposal-top-level-await. As a consequence the **Module Arguments** idea is acceptably resolvable within Node/Browsers anyway by using url parameters (as unique url parameters will trigger multiple module instances) so the dictionary example could be written as: ``` // dictionary.js ... const language = new URL(import.meta.url).searchParams.get("lang") || "en-US"; const languageData = await loadData(new URL(`../langs/${ language }.js`, import.meta.url) export default makeDictionary(languageData) // main.js import englishDict from "./dictionary.js" import spanishDict from "./dictionary.js?lang=es-ES" ``` The only downside to this approach is that there might be redundancy in presence of multiple such args as `import foo from "./foo.js?bar=12&cats=13"` would be different from `... "./foo.js?cats=13&bar=12"` but I think it's relatively unimportant as I can't actually think of a concrete example of multiple arguments. --- Although I actually think in the presence of top-level-await that the **Lazy-Export from** proposal would be even better, as even in the presence of tree-shaking build tools those tools may not be able to determine where a side-effect is actually important or not to the exported values. e.g. Consider the above code, can a tree-shaker viably detect that the above file is (pseudo) side-effect free? With complex usage this may become in general too difficult. Whereas given a static form a tree-shaking tool need not even consider `static export { someExport } from "./someModule.js"` if `someExport` is never actually imported in the receiving code. For example consider the following code: ``` // audioTools.js export { default as audioContext } from "./audioContext.js" export { default as simpleBeat } from "./simpleBeat.js" ... // audioContext.js export default new AudioContext() // main.js import { simpleBeat } from "./audioTools.js" /* Create own OfflineAudioContext */ const ctx = new OfflineAudioContext() ... simpleBeat.connect(ctx,destination) ctx.startRendering().then(...) ``` In this example `audioContext.js` has *real* side-effects (as there can only be up to 6 or so live audio contexts in most browsers and because the module lifetime persists with the page it can't be garbage collected). But yet `audioContext` is never actually used so it's a pointless side-effect. Can a tree-shaking tool detect this? Maybe? But I'm skeptical that tree-shaking tools can detect all of these what I'm referring to as pseudo side-effects. Note that while I'm arguing in the context of build tools, this also applies outside of build tools as it still potentially saves many loads on small sites where a build tool may not be necessary (e.g. dynamic blogs, or so on). Especially in the case of hundreds of exports (e.g. `import { util1, util2 } from "./lodash.js"` could just work only loading the three files `lodash.js`, `lodash/util1.js`, `lodash/util2.js`) as it doesn't actually need to construct the whole module record. If there's any TC39 members that would actually be interested in championing something like this I'd be happy to write some material and draft spec-text to clarify the exact problems and solution I'm proposing in this idea.
thejamesernator at gmail.com (2018-03-05T10:51:59.779Z)
Just as a follow up to these ideas, the first proposal I suggested can be *entirely* resolved with the top level await proposal: https://github.com/ MylesBorins/proposal-top-level-await. As a consequence the **Module Arguments** idea is acceptably resolvable within Node/Browsers anyway by using url parameters (as unique url parameters will trigger multiple module instances) so the dictionary example could be written as: ``` // dictionary.js ... const language = new URL(import.meta.url).searchParams.get("lang") || "en-US"; const languageData = await loadData(new URL(`../langs/${ language }.js`, import.meta.url) export default makeDictionary(languageData) // main.js import englishDict from "./dictionary.js" import spanishDict from "./dictionary.js?lang=es-ES" ``` The only downside to this approach is that there might be redundancy in presence of multiple such args as `import foo from "./foo.js?bar=12&cats=13"` would be different from `... "./foo.js?cats=13&bar=12"` but I think it's relatively unimportant as I can't actually think of a concrete example of multiple arguments. --- Although I actually think in the presence of top-level-await that the **Lazy-Export from** proposal would be even better, as even in the presence of tree-shaking build tools those tools may not be able to determine where a side-effect is actually important or not to the exported values. e.g. Consider the above code, can a tree-shaker viably detect that the above file is (pseudo) side-effect free? With complex usage this may become in general too difficult. Whereas given a static form a tree-shaking tool need not even consider `static export { someExport } from "./someModule.js"` if `someExport` is never actually imported in the receiving code. For example consider the following code: ``` // audioTools.js export { default as audioContext } from "./audioContext.js" export { default as simpleBeat } from "./simpleBeat.js" ... // audioContext.js export default new AudioContext() // main.js import { simpleBeat } from "./audioTools.js" /* Create own OfflineAudioContext */ const ctx = new OfflineAudioContext() ... simpleBeat.connect(ctx,destination) ctx.startRendering().then(...) ``` In this example `audioContext.js` has *real* side-effects (as there can only be up to 6 or so live audio contexts in most browsers and because the module lifetime persists with the page it can't be garbage collected). But yet `audioContext` is never actually used so it's a pointless side-effect. Can a tree-shaking tool detect this? Maybe? But I'm skeptical that tree-shaking tools can detect all of these what I'm referring to as pseudo side-effects. Note that while I'm arguing in the context of build tools, this also applies outside of build tools as it still potentially saves many loads on small sites where a build tool may not be necessary (e.g. dynamic blogs, or so on). Especially in the case of hundreds of exports (e.g. `import { util1, util2 } from "./lodash.js"` could just work only loading the three files `lodash.js`, `lodash/util1.js`, `lodash/util2.js`) as it doesn't actually need to construct the whole module record. If there's any TC39 members that would actually be interested in championing something like this I'd be happy to write some material and draft spec-text to clarify the exact problems and solution I'm proposing in this idea.