dynamic import() polyfill + question
Cyril Auburtin
cyril.auburtin at gmail.com
Sat Apr 22 14:41:59 UTC 2017
If the discussion is about a polyfill for import()
<https://github.com/tc39/proposal-dynamic-import> (not the static import)
it's not too hard:
https://gist.github.com/caub/458cfe944f8abcf7b1aec608d0a878cc
```js
(async()=>{
const [Stuff, {foo, bar}] = await Promise.all(['./x',
'./y'].map(require));
// ..
})()
```
2017-04-22 16:31 GMT+02:00 Andrea Giammarchi <andrea.giammarchi at gmail.com>:
> > Why not just allow `export await` in all export syntactic forms?
>
> that would work for me, and it would be like my initial, and second,
> example: `export default await Promise.all(...).then(...)`
>
> however, just to better understand what you're up to, I wonder if the
> module would be held, in a non blocking way, until all asynchronous exports
> have been resolved (desired) as opposite of introducing complexity for
> hybrid modules where you have to await everything to be sure it won't break
> (shenanigans)
>
> TL;DR unless the following would be possible too, please consider making
> modules available only once fully resolved through their exports
>
> ```js
> import await * as module from './module.js';
> ```
>
> Regards
>
>
>
>
> On Sat, Apr 22, 2017 at 3:08 PM, Matthew Robb <matthewwrobb at gmail.com>
> wrote:
>
>> I know you probably didn't want things to go this direction in the
>> conversation but this made me think up a generic way to do this. Why not
>> just allow `export await` in all export syntactic forms? This would not be
>> the same as top level await but a signal that the export will be the result
>> of an asynchronous operation that follows the await.
>>
>> Then you could potentially do `export default await (async ()=>{
>>
>> })();`
>>
>> On Apr 21, 2017 3:10 PM, "Bradley Meck" <bradley.meck at gmail.com> wrote:
>>
>> > how's that different from a Promise ?
>>
>> `later` is not const and could change over time. Could even be set via
>> something like:
>>
>> ```
>> setInterval(() => later = Date.now(), 1e3);
>> ```
>>
>> On Fri, Apr 21, 2017 at 2:00 PM, Andrea Giammarchi <
>> andrea.giammarchi at gmail.com> wrote:
>>
>>> > let later;
>>> > export default {then(notify) { if (ready) notify(later); else
>>> queue(notify); }}
>>>
>>> how's that different from a Promise ?
>>>
>>> Don't get me wrong, I have a module [1] that does that already (use a
>>> symbol as key and that's it) but yet for an importer, if that has to be
>>> handled like a Promise, then why not just a Promise ?
>>>
>>> This is the bit I don't get.
>>>
>>> Thanks
>>>
>>> [1] https://github.com/WebReflection/broadcast#broadcast--
>>>
>>>
>>>
>>> On Fri, Apr 21, 2017 at 7:38 PM, Bradley Meck <bradley.meck at gmail.com>
>>> wrote:
>>>
>>>> > how asynchronous export helps here ?
>>>>
>>>> >>> I cannot think about a single use case for wanting that: it's not
>>>> usable from within the module, it won't be usable outside unless checked
>>>> via ... an interval ?
>>>>
>>>> As stated in previous email:
>>>>
>>>> >> The previous email was stating there are use cases for updating
>>>> exports.
>>>>
>>>> If you are updating exports that in general means live bindings /
>>>> asynchronous work.
>>>>
>>>> > already covered by `export default new Promise(async () => {})` ,
>>>> right ?
>>>>
>>>> Kind of, this sacrifices live binding since `default` can only ever
>>>> have 1 value. Something could use a thenable to export multiple values over
>>>> time however similar to a live binding:
>>>>
>>>> ```
>>>> let later;
>>>> export default {then(notify) { if (ready) notify(later); else
>>>> queue(notify); }}
>>>> ```
>>>>
>>>> > how is the module consumer supposed to know when these exports are
>>>> ready?
>>>>
>>>> > if it's an event emitted, libraries trusting the event that already
>>>> happened will never know, so we are back to polling, which is a very bad
>>>> approach, IMO, and if the solution is a Promise then it's covered already.
>>>>
>>>> Please read my previous email:
>>>>
>>>> >> The answer is no pattern has been standardized so it depends on
>>>> your proposed solution. A `then()`-able is already in spec and seems like a
>>>> possible choice (though I wouldn't use a Promise); top level await could be
>>>> another but blocks the module graph. TDZ poll/checking on imports could be
>>>> another (though not-preferable) solution. I am sure we could bikeshed other
>>>> approaches.
>>>>
>>>> > so if two importers happen at different times the second importer
>>>> can compromise with undesired features the first one or vice-verssa?
>>>>
>>>> No, ESM modules are only evaluated once. Such checks are most likely
>>>> done up front. However, enabling a debugger for example might cause a new
>>>> set of exports to be loaded/exported.
>>>>
>>>> > So, like I've said, I don't see real-world scenarios for exported
>>>> modules that changes without notice.
>>>> It looks unpractical and undesired.
>>>>
>>>> As stated in previous email:
>>>>
>>>> > Exporting asynchronously doesn't provide any coordination point ...
>>>>
>>>> The rest of my email(s) have been talking about coordination.
>>>>
>>>> On Fri, Apr 21, 2017 at 1:28 PM, Andrea Giammarchi <
>>>> andrea.giammarchi at gmail.com> wrote:
>>>>
>>>>> > It could be something that is being mocked/spied upon.
>>>>>
>>>>> how asynchronous export helps here ?
>>>>>
>>>>>
>>>>>
>>>>> > It could be part of a circular dependency and so the modules do get
>>>>> a hold of eachother without finishing evaluation.
>>>>>
>>>>> already covered by `export default new Promise(async () => {})` ,
>>>>> right ?
>>>>>
>>>>>
>>>>>
>>>>> > It could be that it lazily/async populates its exports due to costs.
>>>>>
>>>>> how is the module consumer supposed to know when these exports are
>>>>> ready?
>>>>>
>>>>> if it's an event emitted, libraries trusting the event that already
>>>>> happened will never know, so we are back to polling, which is a very bad
>>>>> approach, IMO, and if the solution is a Promise then it's covered already.
>>>>>
>>>>>
>>>>>
>>>>> > It could be that it is relying upon context to determine if
>>>>> something should be exported (debug flag etc.)
>>>>>
>>>>> so if two importers happen at different times the second importer can
>>>>> compromise with undesired features the first one or vice-verssa?
>>>>>
>>>>> Dynamic exports are possible since ever on CommonJS world (same as
>>>>> imports) and I've truly rarely seen the need to lazy export or lazy import.
>>>>> Conditional import yes, and conditional exports too but never at distance.
>>>>>
>>>>> So, like I've said, I don't see real-world scenarios for exported
>>>>> modules that changes without notice.
>>>>> It looks unpractical and undesired.
>>>>>
>>>>> Can you point at me at a single module that needs to do that?
>>>>> Maybe I'm missing something.
>>>>>
>>>>> Thanks
>>>>>
>>>>>
>>>>>
>>>>>
>>>>> On Fri, Apr 21, 2017 at 7:18 PM, Bradley Meck <bradley.meck at gmail.com>
>>>>> wrote:
>>>>>
>>>>>> > Let me ask again: as a module consumer, how are you supposed to
>>>>>> know when an export is available?
>>>>>>
>>>>>> The previous email was stating there are use cases for updating
>>>>>> exports.
>>>>>>
>>>>>> The answer is no pattern has been standardized so it depends on your
>>>>>> proposed solution. A `then()`-able is already in spec and seems like a
>>>>>> possible choice (though I wouldn't use a Promise); top level await could be
>>>>>> another but blocks the module graph. TDZ poll/checking on imports could be
>>>>>> another (though not-preferable) solution. I am sure we could bikeshed other
>>>>>> approaches.
>>>>>>
>>>>>> I don't see "None of these haven't been solved already through
>>>>>> better pattern." as a response to all the use cases I described.
>>>>>>
>>>>>> On Fri, Apr 21, 2017 at 1:13 PM, Andrea Giammarchi <
>>>>>> andrea.giammarchi at gmail.com> wrote:
>>>>>>
>>>>>>> None of these haven't been solved already through better pattern.
>>>>>>>
>>>>>>> Let me ask again: as a module consumer, how are you supposed to know
>>>>>>> when an export is available?
>>>>>>>
>>>>>>> On Fri, Apr 21, 2017 at 7:08 PM, Bradley Meck <
>>>>>>> bradley.meck at gmail.com> wrote:
>>>>>>>
>>>>>>>> Could be several reasons, it could be exporting a counter/log that
>>>>>>>> changes over time.
>>>>>>>>
>>>>>>>> It could be something that is being mocked/spied upon.
>>>>>>>>
>>>>>>>> It could be part of a circular dependency and so the modules do get
>>>>>>>> a hold of eachother without finishing evaluation.
>>>>>>>>
>>>>>>>> It could be that it lazily/async populates its exports due to costs.
>>>>>>>>
>>>>>>>> It could be that it is relying upon context to determine if
>>>>>>>> something should be exported (debug flag etc.)
>>>>>>>>
>>>>>>>> Probably plenty more reasons.
>>>>>>>>
>>>>>>>> On Fri, Apr 21, 2017 at 11:58 AM, Andrea Giammarchi <
>>>>>>>> andrea.giammarchi at gmail.com> wrote:
>>>>>>>>
>>>>>>>>> > a Promise cannot change value over time, unlike a live binding.
>>>>>>>>>
>>>>>>>>> when is a module that changes values and without any notification
>>>>>>>>> desirable?
>>>>>>>>>
>>>>>>>>> I cannot think about a single use case for wanting that: it's not
>>>>>>>>> usable from within the module, it won't be usable outside unless checked
>>>>>>>>> via ... an interval ?
>>>>>>>>>
>>>>>>>>> The main point here is that asynchronous import might also
>>>>>>>>> inevitably mean asynchronous exports.
>>>>>>>>>
>>>>>>>>> Early access to unusable modules doesn't seem a real-world
>>>>>>>>> solution to me.
>>>>>>>>>
>>>>>>>>> What am I missing?
>>>>>>>>>
>>>>>>>>> Best Regards
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> On Fri, Apr 21, 2017 at 5:48 PM, Bradley Meck <
>>>>>>>>> bradley.meck at gmail.com> wrote:
>>>>>>>>>
>>>>>>>>>> I have been thinking about this some, I do think there is
>>>>>>>>>> something here, but am not sure it warrants any changes. Exporting
>>>>>>>>>> asynchronously doesn't provide any coordination point so the general idea
>>>>>>>>>> is to export a Promise, but a Promise cannot change value over time, unlike
>>>>>>>>>> a live binding. So, a more appropriate way might be to export a "ready"
>>>>>>>>>> binding that is a Promise. Without some kind of async coordination like a
>>>>>>>>>> `.then()`-able you would also suffer from `undefined` being a possible
>>>>>>>>>> initialized and uninitialized value.
>>>>>>>>>>
>>>>>>>>>> ```
>>>>>>>>>> let later;
>>>>>>>>>> export {later};
>>>>>>>>>> export const ready = someAsyncWork().then(v => later = v);
>>>>>>>>>> ```
>>>>>>>>>>
>>>>>>>>>> This does still mean that `later` can be accessed before it is
>>>>>>>>>> ready, in my opinion somewhat against the idea of a TDZ wanting to wait for
>>>>>>>>>> access to be ready.
>>>>>>>>>>
>>>>>>>>>> I would be interested in something like:
>>>>>>>>>>
>>>>>>>>>> ```
>>>>>>>>>> async let later;
>>>>>>>>>> export {later};
>>>>>>>>>> export const ready = someAsyncWork().then(v => later = v);
>>>>>>>>>> ```
>>>>>>>>>>
>>>>>>>>>> That preserves the TDZ until assignment. Or, something that wraps
>>>>>>>>>> `later` in a non-promise `.then()`-able that `import` understands and can
>>>>>>>>>> unwrap to a live binding.
>>>>>>>>>>
>>>>>>>>>> All of that said, I am not sure this specific of a use warrants
>>>>>>>>>> language changes as I can think of problems with the ideas I have proposed
>>>>>>>>>> as well.
>>>>>>>>>>
>>>>>>>>>> On Fri, Apr 21, 2017 at 11:24 AM, Benoit Marchant <
>>>>>>>>>> marchant at mac.com> wrote:
>>>>>>>>>>
>>>>>>>>>>> I really like that idea
>>>>>>>>>>>
>>>>>>>>>>> On Apr 21, 2017, at 08:22, Andrea Giammarchi <
>>>>>>>>>>> andrea.giammarchi at gmail.com> wrote:
>>>>>>>>>>>
>>>>>>>>>>> nobody has any thought on this ?
>>>>>>>>>>>
>>>>>>>>>>> Maybe the following pattern would be just about enough to solve
>>>>>>>>>>> a generic asynchronous import/export ?
>>>>>>>>>>>
>>>>>>>>>>> ```js
>>>>>>>>>>> export default new Promise(async $export => {
>>>>>>>>>>>
>>>>>>>>>>> const utils = await import('./utils.js').default;
>>>>>>>>>>>
>>>>>>>>>>> $export({module: 'asynchronous', utils});
>>>>>>>>>>>
>>>>>>>>>>> });
>>>>>>>>>>> ```
>>>>>>>>>>>
>>>>>>>>>>> Best Regards
>>>>>>>>>>>
>>>>>>>>>>> On Thu, Apr 20, 2017 at 11:51 AM, Andrea Giammarchi <
>>>>>>>>>>> andrea.giammarchi at gmail.com> wrote:
>>>>>>>>>>>
>>>>>>>>>>>> Even if unpolyfillable through simple `function import() {}`
>>>>>>>>>>>> declaration,
>>>>>>>>>>>> I've managed to create a polyfill/payground for the ESnext's
>>>>>>>>>>>> dynamic import() [1]
>>>>>>>>>>>>
>>>>>>>>>>>> This also made me wonder if there's any plan to provide a way
>>>>>>>>>>>> to asynchronously
>>>>>>>>>>>> export modules that depends on those that use asynchronous
>>>>>>>>>>>> import.
>>>>>>>>>>>>
>>>>>>>>>>>> Since AFAIK modules have no top-level await, the only pattern I
>>>>>>>>>>>> can see right now
>>>>>>>>>>>> to import something asynchronous is the following one:
>>>>>>>>>>>>
>>>>>>>>>>>> ```js
>>>>>>>>>>>> // module ./js/c.js
>>>>>>>>>>>> export default Promise.all([
>>>>>>>>>>>> import('./js/a.js'),
>>>>>>>>>>>> import('./js/a.js')
>>>>>>>>>>>> ]).then([a, b] => {
>>>>>>>>>>>> const module = {a, b, c() {}};
>>>>>>>>>>>> return module;
>>>>>>>>>>>> });
>>>>>>>>>>>>
>>>>>>>>>>>> // module that uses ./js/c.js
>>>>>>>>>>>> import('./js/c.js').then(m => m.default).then(c => {
>>>>>>>>>>>> c.a(); c.b(); c.c();
>>>>>>>>>>>> });
>>>>>>>>>>>> ```
>>>>>>>>>>>>
>>>>>>>>>>>> However, above boilerplate doesn't seem ideal compared with
>>>>>>>>>>>> something like the following:
>>>>>>>>>>>>
>>>>>>>>>>>> ```js
>>>>>>>>>>>> // module ./js/c.js
>>>>>>>>>>>> export default await Promise.all([
>>>>>>>>>>>> import('./js/a.js'),
>>>>>>>>>>>> import('./js/a.js')
>>>>>>>>>>>> ]).then([a, b] => {
>>>>>>>>>>>> const module = {a, b, c() {}};
>>>>>>>>>>>> return module;
>>>>>>>>>>>> });
>>>>>>>>>>>>
>>>>>>>>>>>> // module that uses ./js/c.js
>>>>>>>>>>>> import * as c from './js/c.js';
>>>>>>>>>>>> ```
>>>>>>>>>>>>
>>>>>>>>>>>> But again, AFAIK that's not possible.
>>>>>>>>>>>>
>>>>>>>>>>>> The clear advantage is that the module consumer wouldn't need
>>>>>>>>>>>> to know, or care,
>>>>>>>>>>>> if the loaded module depends on some dynamic, asynchronous,
>>>>>>>>>>>> import,
>>>>>>>>>>>> meaning modules can be updated and eventually moved to async
>>>>>>>>>>>> transparently
>>>>>>>>>>>> for any module consumer.
>>>>>>>>>>>>
>>>>>>>>>>>> As summary, is any solution worth exploring/improving/fixing/pla
>>>>>>>>>>>> nning?
>>>>>>>>>>>>
>>>>>>>>>>>> Thank you.
>>>>>>>>>>>> Best Regards
>>>>>>>>>>>>
>>>>>>>>>>>> [1] https://github.com/WebReflection/import.js#importjs
>>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> _______________________________________________
>>>>>>>>>>> es-discuss mailing list
>>>>>>>>>>> es-discuss at mozilla.org
>>>>>>>>>>> https://mail.mozilla.org/listinfo/es-discuss
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> _______________________________________________
>>>>>>>>>>> es-discuss mailing list
>>>>>>>>>>> es-discuss at mozilla.org
>>>>>>>>>>> https://mail.mozilla.org/listinfo/es-discuss
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>
>>>>>>>>
>>>>>>>
>>>>>>
>>>>>
>>>>
>>>
>>
>> _______________________________________________
>> es-discuss mailing list
>> es-discuss at mozilla.org
>> https://mail.mozilla.org/listinfo/es-discuss
>>
>>
>>
>
> _______________________________________________
> es-discuss mailing list
> es-discuss at mozilla.org
> https://mail.mozilla.org/listinfo/es-discuss
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20170422/f68380b8/attachment-0001.html>
More information about the es-discuss
mailing list