Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

discuss: asynchronous module.import #10956

Closed
WebReflection opened this issue Jan 22, 2017 · 10 comments
Closed

discuss: asynchronous module.import #10956

WebReflection opened this issue Jan 22, 2017 · 10 comments
Labels
discuss Issues opened for discussions and feedbacks. module Issues and PRs related to the module subsystem.

Comments

@WebReflection
Copy link
Contributor

I am not fully sure this is the right place to discuss CommonJS patterns but I'd like to understand if there's the possibility to discuss a possible new Module.prototype method like the following one:

// Module as module.constructor
Module.prototype.import = function (path) {
  return new Promise(res => res(this.require(path)));
};

This would enable asynchronous import and asynchronous exports out of the box.

// modules as we know: converter.js
const crypto = require('crypto');
module.exports = {
  sha256: (str, secret = '') =>
    crypto.createHmac('sha256', secret)
          .update(str)
          .digest('hex')
};

// same good old synchronous flavor
const converter = require('./converter');
console.log(converter.sha256('yolo'));

// module.import asynchronous flavor
module.import('./converter')
.then((converter) => {
  console.log(converter.sha256('yolo'));
});

To export asynchronously the module has to simply export a Promise

// generic async export
module.exports = new Promise(define => {
  // some asynchronous operation ...
  define({my:'module'});
});

// asynchronous converter.js
module.exports = module.import('./crypto')
.then((crypto) => {
  // return the module to export
  return {
    sha256:(str, secret = '') =>
      crypto.createHmac('sha256', secret)
            .update(str)
            .digest('hex')
  };
});

Multiple dependencies can be easily handled via Promise.all.

module.exports = Promise.all([
  './awe',
  './some'
].map(m => module.import(m))).then(modules => {
  const [awe, some] = modules;
  return {awe, some};
});

I'm testing already these patterns on both server and client [1], and there's nothing I can spot that could cause troubles, in terms of backward compatibility, but it could enable new kind of possibilities for both client and server.

Thank you for your consideration.

[1] https://medium.com/@WebReflection/asynchronous-module-import-path-b9f56675e109#.ehnofaj2q

@mscdex
Copy link
Contributor

mscdex commented Jan 23, 2017

Have you considered joining the discussion on ES modules? I think discussing features like async module loading is best had there IMHO.

@mscdex mscdex added discuss Issues opened for discussions and feedbacks. module Issues and PRs related to the module subsystem. labels Jan 23, 2017
@WebReflection
Copy link
Contributor Author

WebReflection commented Jan 23, 2017

@mscdex I've already mentioned above playground there and they believed I was just sponsoring my library, while I'm actually proposing a CommonJS pattern, which is also something they're not interested in (if they were, the current ES2015 import/export status wouldn't be where it is now).

The idea is to use the only two things agreed by TC39, the Promise based solution, which is future friendly with async and await, and the import name, which cannot be polyfilled on the global scope anyway since it's a reserved word.

Would NodeJS community consider implementing this feature, maybe they will have a precedent to consider and work with, instead of the other way around.

Does this answer your question?

@mscdex
Copy link
Contributor

mscdex commented Jan 23, 2017

What I meant was why not voice your support for async ES module loading instead of adding it on to CommonJS modules?

@WebReflection
Copy link
Contributor Author

more than bringing their own proposal into a well known and used env as NodeJS via 3 lines of code and a little utility library that demonstrates all problems mentioned in there are solved, I am not sure what to do.

I am active in the ML and I've mentioned this approach already but we all know it takes ages for all vendors to agree and implement something so here there's hopefully more freedom, being CommonJS a de-facto standard?

Since AFAIK the agreement on the Promise is there already, this idea is future friendly.

Or you are saying that any new feature in NodeJS should be agreed as ECMAScript standard first?
This one seems like a cheap addiction full of wins, doesn't it?

I've opened a thread here to discuss what NodeJS people think (so yes, I might keep bothering TC39 people too with exact same idea, but they already have it there)

@joyeecheung
Copy link
Member

At this point creating another defacto standard on our own instead of collaborating with other vendors and make it a ECMAScript standard(even though that would be slow) would only make things worse IMHO. What are the benefits of this proposal over dynamic import(except it would be faster to roll out)? What will happen to this API when dynamic import becomes fully usable?

@WebReflection
Copy link
Contributor Author

What are the benefits of this proposal over dynamic import?

Dynamic import is unpolyfillable (reserved word, unless you pass through global.import() each time) while module.import is potentially already available and polyfilled for every NodeJS user since Promise have landed in code.

My lil' utility makes this experimentation easily portable to any browser too so that developers could start using this right away.

Every modern API is also shipping Promise based, see customElements.whenDefined('com-name') or document.whenReady, all things that compose well with this module.import but also on NodeJS it happened more than once that I return a module synchronously while I am initiating a DB connection asynchronously (talking about DBs, MQs, and friends).

This pattern would benefit both worlds and it could do it sooner than dynamic import.

except it would be faster to roll out

Well, that's not something to ignore neither, and quite possibly one of the major points.

Having an already adopted solution also could speed-up rolling out on standards since those work counting implementors too. (it's in ES stages process).

They won't adopt CommonJS, it was never the plan, but they can verify what they have proposed is already working at scale.

What will happen to this API when dynamic import becomes fully usable?

What is happening, or will happen, to require once static synchronous import will be widely available?

Transpiled code will fallback to synchronous require or to dynamic module.import until every vendor shipping an ES engine will be onboard with the dynamic loader.

In other words, this 3 LOC feature can move both client and server forward with, as far as I can tell, full backward compatibility and zero risks in shipping it.

Eventually, like every feature in every language, we'll see low adoption but if it doesn't go out we're somehow in a Catch-22 like situation, hence my proposal to roll it on the most used CommonJS based environment.

@joyeecheung
Copy link
Member

joyeecheung commented Jan 23, 2017

I see, so this proposal is like another bridge between require and import filling in the gaps of async loading?

I think this discussion should go to https://github.com/nodejs/node-eps/? (Not sure if something like this has been raised there before).

EDIT: And yes, this is irrelevant to import() because it's a pure NCJS thing. I am not sure if this counts as an implementation of import() for TC39 to consider and speed up the process of import() though, because they are not the same thing.

@WebReflection
Copy link
Contributor Author

I see, so this proposal is like another bridge between require and import filling in the gaps of async loading?

hopefully it's the only needed bridge, accordingly with current dynamic import() proposal, and yes, it could fill the gaps of async loading.

I am not sure if this counts as an implementation of import() for TC39 to consider and speed up the process of import() though, because they are not the same thing.

Like I've said, this idea is indeed strictly a CommonJS related one but it's fully based on this standard prototype/proposal without any of those issues described in there.

Thanks for the hint on node-esp, I wasn't aware of the special repo for these kind of discussions.

I'l try to search for similar proposals and, if none, I'll PR this one. Cheers

@joyeecheung
Copy link
Member

Glad to help. I think this issue over here can be closed now.

@joyeecheung
Copy link
Member

Also I think nodejs/node-eps#39 (diff) is discussing the same thing as the proposal?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
discuss Issues opened for discussions and feedbacks. module Issues and PRs related to the module subsystem.
Projects
None yet
Development

No branches or pull requests

3 participants