vite icon indicating copy to clipboard operation
vite copied to clipboard

Support `import.meta.resolve(…)`

Open lgarron opened this issue 2 years ago • 5 comments

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.url in different ways, which can cause compatibility bugs. It would be nice to avoid the need to publish code that import.meta.url for 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 that new URL("bare-import", import.meta.url) has two meanings (import a relative file named e.g. bare-import.js, or import the package bare-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

lgarron avatar Sep 28 '23 21:09 lgarron

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.

sapphi-red avatar Sep 29 '23 01:09 sapphi-red

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.

lgarron avatar Sep 29 '23 02:09 lgarron

@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.

Swivelgames avatar Oct 11 '23 19:10 Swivelgames

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.

lgarron avatar Oct 12 '23 08:10 lgarron

So... did anybody end up writing a plugin for this? :)

nicolo-ribaudo avatar Jun 20 '25 19:06 nicolo-ribaudo

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 avatar Aug 03 '25 16:08 remorses

@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.

Swivelgames avatar Aug 04 '25 18:08 Swivelgames