nodejs / node

Node.js JavaScript runtime ✨🐢🚀✨
https://nodejs.org
Other
107.41k stars 29.52k forks source link

Uncaught error with `--experimental-import-meta-resolve` #55518

Open ph-fritsche opened 1 day ago

ph-fritsche commented 1 day ago

Version

22.10

Platform

Linux be964f1f5acb 6.10.4-linuxkit #1 SMP PREEMPT_DYNAMIC Wed Oct  2 16:39:54 UTC 2024 x86_64 Linux

https://hub.docker.com/layers/library/node/22-alpine/images/sha256-c5088ba04c8fcce84e45c9ab8767af401424943a8bfd90ede5a68aefc4f42808

Subsystem

No response

What steps will reproduce the bug?

Run with --experimental-import-meta-resolve:

function resolve(specifier, parentURL) {
    console.log(`\n§ ${parentURL} --> ${specifier}`)
    try {
        console.log(`Resolved: ${import.meta.resolve(specifier, parentURL)}`)
    } catch (e) {
        console.log(`Error: ${e.code}`)
    }
}

resolve('foo', 'file:///bar.js')
resolve('./foo.js', 'http://example.com/bar.js')
resolve('file:///foo.js', 'http://example.com/bar.js')
resolve('foo', 'http://example.com/bar.js')

How often does it reproduce? Is there a required condition?

Always reproduces

What is the expected behavior? Why is that the expected behavior?

A catchable error that the specifier can't be resolved. This allows to provide a helpful error message that the user should add a custom resolver/loader.

What do you see instead?

§ file:///bar.js --> foo
Error: ERR_MODULE_NOT_FOUND

§ http://example.com/bar.js --> ./foo.js
Resolved: http://example.com/foo.js

§ http://example.com/bar.js --> file:///foo.js
Error: ERR_INVALID_URL_SCHEME

§ http://example.com/bar.js --> foo

  #  node[1799]: static void node::modules::BindingData::GetPackageScopeConfig(const v8::FunctionCallbackInfo<v8::Value>&) at ../src/node_modules.cc:403
  #  Assertion failed: file_url

----- Native stack trace -----

----- JavaScript stack trace -----

1: getPackageScopeConfig (node:internal/modules/package_json_reader:132:33)
2: packageResolve (node:internal/modules/esm/resolve:792:43)
3: moduleResolve (node:internal/modules/esm/resolve:907:18)
4: defaultResolve (node:internal/modules/esm/resolve:1037:11)
5: defaultResolve (node:internal/modules/esm/loader:650:12)
6: #cachedDefaultResolve (node:internal/modules/esm/loader:599:25)
7: #resolveAndMaybeBlockOnLoaderThread (node:internal/modules/esm/loader:615:38)
8: resolveSync (node:internal/modules/esm/loader:632:52)
9: resolve (node:internal/modules/esm/initialize_import_meta:33:25)
10: resolve (file:///workspaces/nodejs-import-meta-resolve/[eval1]:6:46)

Aborted

Additional information

No response

RedYetiDev commented 1 day ago

The assertion is failing because it expects the URL's protocol to be file:, when it is http:

cedrick-ah commented 13 hours ago

I would like to work on this. In the function moduleResolve in lib/internal/modules/esm/resolve.js when the protocol of the parsed parentURL is not file the parentURL is returned. Instead of just returning the parentURL, can we do something like this in the function moduleResolve:

  if (resolved.protocol !== 'file:') {
     throw new ERR_INVALID_URL_SCHEME(resolved.protocol);
  }
RedYetiDev commented 12 hours ago

No, That wouldn't work. Under the hood, the issue is because it's trying to read the package configuration for the URL, which it can't do. There are cases where a URL can be used, this is not one of them.

cedrick-ah commented 12 hours ago

The assertion is failing because it expects the URL's protocol to be file:, when it is http:

According to this, can we then check for the URL protocol in throwIfInvalidParentURL?

RedYetiDev commented 12 hours ago

I believe @JakobJingleheimer may know more than I (regarding the package.json reading) (if not, sorry for the ping)

JakobJingleheimer commented 7 hours ago

The provided code sample looks like a loader hook. If so, import.meta.resolve() is not available within loaders.