dynamic import() polyfill + question
Andrea Giammarchi
andrea.giammarchi at gmail.com
Sat Apr 22 14:50:11 UTC 2017
Cyril the discussion is now rather about about asynchronous export.
However, what you linked is not a polyfill for import, that's more like a
half backed require.
The polyfill for dynamic import where you actually use `import(path)` as
specified on stage 3 is here:
https://github.com/WebReflection/import.js
The universal attempt to add `.import()` as CommonJS module is here:
https://github.com/WebReflection/common-js
Latter does what you wrote but on both client and server (it also probably
resolves relative paths in a slightly different (more accurate?) way.
That pattern never convinced CommonJS chaps that believes nobody wants
asynchronous requires in this world (I actually do as much as I want
asynchronous exports too ^_^)
Regards
On Sat, Apr 22, 2017 at 3:41 PM, Cyril Auburtin <cyril.auburtin at gmail.com>
wrote:
> 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/planning?
>>>>>>>>>>>>>
>>>>>>>>>>>>> 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
>>
>>
>
> _______________________________________________
> 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/77ffc61a/attachment-0001.html>
More information about the es-discuss
mailing list