-
Notifications
You must be signed in to change notification settings - Fork 44
Feature: Retrievable module metadata #104
Comments
I'm not sure what this feature is. Is this just asking for capabilities like If it's the later this could (perhaps weirdly) be solved by // Would get the metadata of another file resolved
// in the same way as import()
import.meta.metadataFor('./foo.mjs'); |
Hey, I think you might be missing the use cases document - https://docs.google.com/document/d/10BBsIqdAXB9JR2KUzQGYbCiVugYBnxE4REBakX29yyo/edit This use case by @jkrems
This can for example be done by Please don't hesitate to speak up if there is anything unclear about the discussion here. |
|
The use case as written was about everyday reading/editing of the code. E.g. it was about a person reading the code being able to quickly find the file if they'd switch to a terminal or a file browser. With browser ESM that's super easy (right now) but CommonJS scores much lower here. |
Sorry for going off on a tangent and in detail I found that part very interesting as there is possibly unique opportunities to be considered:
Normally, module resolution systems are either a) browser (per spec) or node (per config) runtime or b) runtime-emulating with or without a mapping layer for development. In other words, at the core of every non-runtime module resolution implementation is some logic that emulates to some degree the target runtime, and those implementations may or may not include additional layers for mapping between source and target specifiers. Given that most development workflows today involve at least one such implementation. Add to that the fact that each implementation (even if flawless) often involves additional configuration points. It is easy to imagine how all these different systems exponentially complicate the development experience, limit it or sometimes even break previously existing projects. Just consider how the adoption of something as widely accepted as ES modules has been impacted across the various tools. Node is in a very unique position at the moment when redesigning the module system in that it can take over the most basic module resolution layers and provide a Module Resolution API shared across runtime and development use cases. Essentially, the module system would be clearly broken down to a) resolution and b) evaluation or execution. The latter subsystem is strictly employed by Node's runtime, where it would depend on a single instance of the former following the specific runtime target configuration. In that sense, I can imagine that other node-based development tools (ie Babel, CoffeeScript, TypeScript... etc) can also create separate instances of the Module Resolver with a specific configuration profile for some runtime target. And at the same time, debugger simply use the same instance of the Module Resolver used by Node's runtime or in more exotic cases simply decorate or extend that instance which can be useful for overloading, hot reloading, or VM. This divide can lend itself very nicely across a number of features. |
This sounds like a great suggestion. Do you mind adding one or more use cases to the use cases doc that cover this? And in the meeting, assuming a feature gets created to correspond with those use cases, this can get is own feature issue. |
@jkrems That actually ended up as a separate feature: #103. That’s just how it was in the features document; in discussion I guess the one use case got spun out into two features. Maybe this one wasn’t intended from the use case, but it seems a reasonable feature request on its own. |
@GeoffreyBooth after the much needed hours to catch up on what I missed over the past three weeks (away due to family emergency) I just added 4 use cases that kind of beg the feature — it's hard to not be biased when you have feature in mind.
So what's next? I have dedicated time today and really want to get back on track with our efforts. |
If we put something on |
@bmeck it would be way cooler if we could make If we can't, then if we go with |
With or without transparent interop, fwiw, |
Given top-level-await just made stage 2 I don't really see this as a problem. I realize I changed my mind from last week - but then again last week I didn't know it was making progress and this week it's stage 2 so there's that. |
Top-level await doesn't change this discussion in the slightest, imo - TLA is no different than a |
@ljharb I'm sorry, I don't understand that - would you mind explaining or showing some code that demonstrates this issue? |
// CJS
module.exports.foo = 3;
module.exports.bar = undefined;
fetch('some JS file').then(() => {
module.exports.bar = 1;
module.exports.foo = 4;
}); // ESM without TLA
export let foo = 3;
export let bar;
fetch('some JS file').then(() => {
bar = 1;
foo = 4;
}); // ESM with TLA
export let foo = 3;
await fetch('some JS file');
export let bar = 1; // this will be hoisted above the `await`, but not evaluated until here
foo = 4; All three of these modules start out exporting "foo" set to |
As I understand how top-level await should work, it is different because the importer of |
@targos you are wrong; the instant the TLA occurs, the importer resumes, so they will see identical behavior in all three cases. |
So the request here is explicitly for importing modules completely synchronously? Would you mind motivating this with a real-world use case? I think that TLA addresses the use cases we discussed so far. Maybe I just missed one. If there is another use case that requires the synchronous behavior we should add it to the list. |
@benjamingr there's already use cases in the doc that require synchronous import of CJS as a part of transparent interop; this specific issue i believe would be addressed by |
I just followed up with @domenic and the current intention of the TLA proposal is that the parent module would not execute until after the child resolved In the below case, the module would log 4, not 3
|
@MylesBorins that's very confusing to me, and that's something we need to address separately in that proposal. |
@ljharb evaluation from TLA blocks dependents until end of source text is reached. It does not let dependents evaluate immediately after the first |
@ljharb - I believe top-level await significantly changes the ESM landscape (funny how the feature is "just" called "top-level await"). And all because of default export. Assume a module with this code (and assume
This module MUST be loaded asynchronously—and all of it's top-level Why does this significantly change the ESM landscape? Because, from what I can see, this module cannot be transpiled to CJS!. No amount of babeling will make this work. Top-level await transforms ESM from "could be synchronous" to "must be asynchronous". And this is huge. It is finally realising the benefits of ESM's asynchronicity. |
Are you sure this wouldn't transpile to exporting |
TLA advanced to stage 2 prior to my having this understanding; I’ll revisit this with the committee next time it comes up. |
This thread morphed into a bit more on TLA. We should open a new issue to discuss TLA specifically or move discussion to the TLA repo. |
Yes, I asked @MylesBorins about it in one of the modules meetings, when we discussed top-level await, because I knew that the answer to that would determine whether it was just top level await, or a whole breaking change from the babel-model of synchronous loading. |
Could we change the title of this feature here to "Provide resolver API" perhaps? As it sounds like it is being confused with module metadata which actually doesn't seem to have its own feature issue currently. |
This seems like a duplicate of #103 to me, as they both reference the same use case? |
See #103 (comment) This issue is about getting programmatic access to metadata of imported modules. |
@demurgos if you look at the original post of both, they come from the same use case. The exact text of the use case is copied in #104 (comment). |
It is possible to retrieve metadata about a module being imported via an
import
statement.Use case 13.
The text was updated successfully, but these errors were encountered: