-
Notifications
You must be signed in to change notification settings - Fork 72
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
How could import.meta.resolve() behave? #79
Comments
Would another alternative be "return a resolution token"? E.g. something that can be passed into <script type="module">
// Inside of https://example.com/foo.html
const resolution = import.meta.resolve('jquery');
linkEl.href = resolution; // "import:https://example.com/foo.html:jquery"
</script> EDIT: The browser would be free to replace/resolve these so that copy link gets the resolved value etc.. |
I think that's strictly inferior to the last option, as it means creating a new opaque useless type that just needs to get translated into the useful type ( In particular, I don't think there'd be much support for implementing that in browsers, whereas there's definite existing support for the |
As mentioned in #84 (comment) I'm still not sure we should support network round-trip fallbacks due to their performance concerns. If we were to restrict fallbacks to only working for checks that can be done synchronously such as |
I think that @jkrems approach would be more useful is if instead of an opaque type there was a new type like |
I could definitely work with a version of I share @guybedford's concerns about fallback performance/predictability and would probably avoid using fallbacks personally, but I appreciate the importance of making the API consistently async. In the future, we might come up with additional reasons (even more compelling than fallback support) why module resolution needs to be async, and I think we'd be glad we chose a generic solution to the problem (such as returning a On a different note, would it be possible to do |
@benjamn the latest version of Node.js 13 being released soon will be shipping with a flagged implementation of |
@guybedford Thank you so much for working on that! |
I think the primary reason to use The only overlap I could imagine actually happening with fallbacks and resolve is if either a built in module provides images or fonts or if increased resilience is needed. If assets served using Fastly had a fallback, a lot of headache could have been prevented during the recent incident. A more appropriate solution than to have The URL could be something like If this is considered a viable future path I propose having As you mentioned, http requests as a side effect of calling a resolver function is pretty iffy. Having the I believe this presents a pretty solid case for synchronous |
|
Related: #75, #18, #76, whatwg/html#3871.
Background: What is import.meta.resolve()?
The original idea of
import.meta.resolveURL(x)
was that it would be sugar for(new URL(x, import.meta.url)).href
. So, you could doimport.meta.resolveURL("./x")
insidehttps://example.com/path/to/y
and you would get"https://example.com/path/to/x"
.But note that in this formulation, you could also do
import.meta.resolveURL("x")
and get the same result. That's a little strange, sinceimport "x"
would not give you that URL.It would also be ideal if we could do, like Node.js's require.resolve(), a function that gave you a URL from a "package name", of the type provided by import maps. Let's call this
import.meta.resolveMapped()
. So for example, given the simple example map from the readme athttps://example.com/index.html
,import.meta.resolveMapped("lodash")
would give"https://example.com/node_modules/lodash-es/lodash.js"
.We then noticed that having two functions is confusing and redundant. Let's merge them! The result is
import.meta.resolve(x)
, which gets the URL that would be fetched by the module system if you didimport(x)
.Side note: what are the use cases?
We don't have a great list of canonical use cases for this function. whatwg/html#3871 has some, and elsewhere in this issue tracker people like @bicknellr and @justinfagnani have mentioned web components-related use cases.
Maybe gardening up a master list, with code examples, would be a good next step.
The problem: fallbacks
This proposal's introduction of fallbacks for user-supplied packages throws a wrinkle into our plans. In particular, there's no longer a synchronous way to figure out what to do in the "package" case. E.g. in that example, it's no longer clear what
import.meta.resolveMapped("jquery")
, orimport.meta.resolve("jquery")
, should return.Solution ideas
Return an array
That is,
import.meta.resolve("jquery")
returns an array containing the normalized absolute URLs that would be potentially used, e.g.["https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js", "https://example.com/node_modules/jquery/dist/jquery.js"]
.This seems hard for consumers to code against, and makes it hard to refactor between fallbacks and no-fallbacks.
Return a time-varying value
For example, it could return
null
, or an array like the above, while resolution is pending. Once resolution happens (via some actual fetch), it could return the resolved-to URL.This similarly seems hard for consumers to code against.
Return a promise
The drawback here is developer ergonomics. E.g. if you are trying to use this inside a component, in order to programmatically set up
linkEl.href = import.meta.resolve("jquery")
, you no longer can; you need to make that async.This could become less-terrible with top-level await, plus of course the usual mitigations like web packaging/preload/etc. to make sure that top-level await is not overly blocking.
Lazy
In this variant, calling
import.meta.resolve()
does not do any fetches itself. Instead it waits for some actual fetch to happen (e.g. viaimport()
or the use of animport:
URL). The promise may then end up pending for a long time.This feels like a bit of a footgun.
Eager
In this variant, calling
import.meta.resolve()
causes a fetch to happen, which updates the appropriate resolution cache (see #76 for some discussions on what that means).This feels kind of inappropriate for a resolution function to perform I/O.
Punt on this
For example, return
null
for all fallback cases (except maybe we could do built-in module cases?).This still makes refactoring hard; you could break parts of your app by moving from no-fallback to fallback.
Return a request, or a promise for a response
In this variant we get even further from what is typically thought of as a "resolution" function. Instead we return something which could be consumed by various endpoints that currently take a URL. This is a long-standing idea, see whatwg/fetch#49 and whatwg/html#3972. But it might solve all the same use cases.
So far I like this the most. It needs a bit more exploration, but it seems like it could work.
The text was updated successfully, but these errors were encountered: