whatwg / loader

Loader Standard
https://whatwg.github.io/loader/
Creative Commons Zero v1.0 Universal
607 stars 45 forks source link

It should be possible to synchronous retrieve a "loaded and ready" module's export object #130

Open concavelenz opened 8 years ago

concavelenz commented 8 years ago

I'm basically looking for a "retrieve X if present" without initiating a load.

In order to lookup a module from the registry, the "key" must be obtained, the "key" is only available via the "resolve" method (the key is loader defined so unpredictable), and the resolve method returns a promise which will never provide a value synchronously.

concavelenz commented 8 years ago

I have two use cases for this: (1) conditionally use code if it is present. (2) make ES6 modules available to traditional scripts by delaying the loading of those script until after the known ES6 module dependencies are available, and then allow the script to retrieve the module synchronously as they are loaded and evaluated.

caridy commented 8 years ago

(1) conditionally use code if it is present.

Are you talking about polyfills by any chance? Who is responsible for importing the code in the first place?

(2) make ES6 modules available to traditional scripts by delaying the loading of those script until after the known ES6 module dependencies are available, and then allow the script to retrieve the module synchronously as they are loaded and evaluated.

Interesting. In this scenario I suspect you will need a master puppet that will import the modules, wait for them to be ready, and then evaluate the script. Similar scenario happens today with modules compiled with browserify/webpack, and somehow, the communication between the two pieces running a different modes (async vs sync) happens via some global variable or function. Still, you should be able to do:

let mod = System.loader.registry.get('a-module-key').module; // flaky
mod.foo('do something');

My argument here is: if your script is already using the loader, and knows the key of the module, why not just use the import() mechanism? If the issue is not having to rely on an async process because of the ergonomics of the code, top level await my help:

let mod = await System.loader.import('my-module'); // robust
mod.foo('do something');
concavelenz commented 8 years ago

No, not polyfills, think a optional logging library or some such thing.

concavelenz commented 8 years ago

I should be specific about what my original motivation is here: I am trying to build a bridge between current module systems and ES6 modules. My goals were:

My general line of approach was this:

And what I was looking for was the syntax to synchronous access the "load and ready" scripts: except there isn't any. What I was expecting was something like:

   var foo = System.loader.getModuleIfPresent('./foo'); // or similar method

Such a system would need to gather needed dependencies server-side but would not need to modify any of the files. However, no such API exists. System.loader.registry.get is close but it needs a key something the code author does not have (as the value is left to the loader, it is impossible to predict). So I left with poor choices:

It isn't at all clear what the use case a async "resolve" step is trying to support.

caridy commented 8 years ago

I will discuss the use-case with other folks in upcoming weeks, but for me, it smells. Think about how do you do this today with scripts only? And work your way back from that.

If your scripts can't use the loader (it seems), then create your own global registry from where they can get what they need, e.g.:

var legacyRegistry = {}; // this could be `window` as well.
System.loader.import('foo').then((mod) => {
     legacyRegistry['<whateverIdentifierAre>'] = mod;
}).then(() => {
     // load scripts that will rely on `legacyRegistry`
});
concavelenz commented 8 years ago

Right, there I have to (a) a new API to use the legacyRegistry (b) create a means of resolving the relative paths used in the script. I want to avoid (a) and in the general case (b) isn't currently possible as the "name" of the script isn't known.

concavelenz commented 8 years ago

Is there any update on this? I'm still haven't seen any proposal to solve circular imports in a meaningful way. "import(...).then(...)" has the wrong timing.