Support `import.meta.resolve(…)`
Description
Vite and other bundlers support using new URL("path", import.meta.url) to resolve relative paths.
This was a useful convention for a while, but now we have import.meta.resolve(…) to express a relative path resolution.
It is supported by all major browsers and all major runtimes.
Suggested solution
Recognize and transpile import.meta.resolve(…) as part of the import graph. It would be pretty similar to dynamic import(…) but without actually importing code.
- For recent target environments it can be left as
import.meta.resolve(…)(just transform the argument). - For older target environments, it can be transpiled down to
new URL(…, import.meta.url).import.meta.resolve(…)is not an ECMAScript feature, but I would recommend classifying it as ES2022 or ES2023 since all major browsers and runtimes landed support over the last year.
Alternative
The existing new URL(…, import.meta.url) support could be considered sufficient. However, this has significant drawbacks for library authors:
- For web worker code, it requires an instantiation attempts for each relative path resolution fallback. These can be slow. If you want your library to work on a CDN, you also have to perform each attempt a second time using a trampoline. My library currently performs seven attempted worker instantiations, but it could be reduced to one or two if bundlers supported
import.meta.resolve(…). - Bundlers transform
import.meta.urlin different ways, which can cause compatibility bugs. It would be nice to avoid the need to publish code thatimport.meta.urlfor relative path resolution. - Going by the spec,
new URL(…, import.meta.url)does not support bare imports. However, some bundlers overload the syntax to allow this. This means thatnew URL("bare-import", import.meta.url)has two meanings (import a relative file named e.g.bare-import.js, or import the packagebare-import), which means that a library install can break unrelated working code due to ambiguity.import.meta.resolve(…)supports package (or import map) paths without ambiguity.
Additional context
No response
Validations
- [X] Follow our Code of Conduct
- [X] Read the Contributing Guidelines.
- [X] Read the docs.
- [X] Check that there isn't already an issue that request the same feature to avoid creating a duplicate.
Recently I wrote down some thoughts: https://github.com/vitejs/vite/discussions/14405
IMO it'd be nice to implement this as a plugin first before including it to the core.
Recently I wrote down some thoughts: #14405
ooooh, glad to see it! 🤩
IMO it'd be nice to implement this as a plugin first before including it to the core.
That does look like that's been a good prototyping path in the past!
For what it's worth, as a library author I have two main concerns:
- There is no single interoperable way to publish web worker instantiation code that works with all bundlers out of the box.
new URL(…, import.meta.url)got close, but not quite. - I can put a lot of work into using standardized vanilla JS workarounds, but people will still ask me what went wrong if my workarounds cause other interoperability issues.
Now that import.meta.resolve(…) is the interoperable solution supported by all browsers and runtimes, it would save me lot of headaches for it to work out of the box in a few major bundlers (particularly Vite). So if there's something that makes it as easy as possible to land in the core initially (e.g. leaving out baseURL support initially), this would help wrap up over a decade of pain for library authors like me.
I'd also be happy help author a plugin or a PR if it helps, but unfortunately I wouldn't be able to commit any time to ongoing maintenance.
@sapphi-red I would have to agree with @lgarron on this one. This is core language feature. And the benefits of including import.meta.resolve() as a first-class citizen to the core, rather than an afterthought, would resolve some of the issues that people have run into with interoperability issues. Not to mention that, in reality, it may never end up making it in to the core if it's introduced as a plugin now. It would save a lot of headache down the road if it was included in core from the get-go.
I drafted a PR for this by adapting assetImportMetaUrl.ts. Unfortunately, it's not very effective:
- The build still inlines workers by default.
- https://github.com/vitejs/vite/issues/6757 doesn't seem to allow an explicit override (and would not be a sufficient workaround for me)
- I can't test this with the library that I need to (and the implementation would also still not be usable for people using our library), due to #14499 and #7015.
Also, https://github.com/vitejs/vite/issues/11823 is rather funny. 😄
I could use suggestions on a path forward.
So... did anybody end up writing a plugin for this? :)
Adding support for import.meta.resolve would allow creating import maps that do not duplicate the code of npm dependencies, which is required to be able to dynamically import React components from an url at runtime.
const mapScript = document.createElement('script');
mapScript.type = 'importmap';
mapScript.textContent = JSON.stringify({
imports: {
react: await import.meta.resolve('react'),
'react/jsx-runtime': await import.meta.resolve('react/jsx-runtime')
}
}, null, 2);
document.head.append(mapScript);
Related to https://github.com/vitejs/vite/issues/2483
@remorses 100% agree. There's a lot of inherent utility in supporting import.meta.resolve, especially in the use-case you outlined where it can contribute to code-splitting and chunk generation.