Node: Absolute Windows paths are handled as invalid URL path in ESM import()

Created on 13 Aug 2020  路  13Comments  路  Source: nodejs/node

  • Version: v14.8v0
  • Platform: Windows
  • Subsystem:

Related: https://github.com/nodejs/node/issues/31710

What steps will reproduce the bug?

Windows paths are interpreted as invalid file URL. In Linux and Mac, the issue can't be reproduced.

Fail

await import("D:\repositories\fastify-autoload\routes\hello.mjs")

Works

await import(url.pathToFileURL("D:\repositories\fastify-autoload\routes\hello.mjs").href)

Root cause

https://github.com/nodejs/node/issues/31710#issuecomment-587211387

What is the expected behavior?

Interpret windows paths as valid URL paths so we can provide consistent cross-platform behaviour.

What do you see instead?

Error [ERR_UNSUPPORTED_ESM_URL_SCHEME]: Only file and data URLs are supported by the default ESM loader
    at Loader.defaultResolve [as _resolve] (internal/modules/esm/resolve.js:698:11)
    at Loader.resolve (internal/modules/esm/loader.js:82:40)
    at Loader.getModuleJob (internal/modules/esm/loader.js:226:28)
    at Loader.import (internal/modules/esm/loader.js:161:28)
    at importModuleDynamically (internal/modules/cjs/loader.js:1144:27)
    at exports.importModuleDynamicallyCallback (internal/process/esm_loader.js:27:14)
    at loadPlugin (D:\repositories\fastify-autoload\index.js:118:5)
    at D:\repositories\fastify-autoload\index.js:28:12
    at Array.map (<anonymous>)
    at fastifyAutoload (D:\repositories\fastify-autoload\index.js:27:29) {
  code: 'ERR_UNSUPPORTED_ESM_URL_SCHEME'
}

@mcollina

ES Modules feature request

Most helpful comment

What I think would be helpful is adding a check in the ERR_UNSUPPORTED_ESM_URL_SCHEME constructor which checks if the url's scheme is a single letter and the system is on windows, and then offering that you probably want to prefix it with file://

All 13 comments

cc @nodejs/modules

This behavior isn't restricted to windows paths, the same is true for absolute Unix paths as well. The module import specifiers only support URLs, not file paths. To import file paths, they need to be converted to URLs first on all platforms (like you mentioned).

The general problem with supporting both URLs and file paths is that some URLs are also valid (but different!) file paths and vice versa. We decided to go with URLs over file paths to be consistent with other runtimes (e.g. browsers) that are also using URL-based import specifiers.

Do you mean that /mnt/c/Users/starptech/test.mjs is a valid URL and file path in Linux and MAC? or what's the reason that it doesn't fail on all OS?

@StarpTech Yes, /mnt/c/Users/starptech/test.mjs is both a valid absolute POSIX file path and a valid host-relative file: URL. If resolved from file:///any/other/path, the host-relative URL happens to resolve to the same file. But this is coincidence, not guaranteed. Other examples:

  • /mnt/c/Users/starptech/my%20test.mjs:

    • POSIX file path: Valid! It's a file that has a literal percentage sign followed by a "20" in its path.
    • Host-relative URL: Valid! But the filename has a space in it, not a percentage sign. It's a different file than the posix file path interpretation.
  • /mnt/c/Users/starptech/%A.mjs:

    • POSIX file path: Valid! It's a file that has a literal percentage sign followed by an "A" in its path.
    • Host-relative URL: Not valid! Or rather, will fail while trying to convert it to a filename.

Not to mention that host-relative URLs are host-relative. Which means that even the "valid" cases that only use alphanumerical characters with slashes (the characters that happen to be interpreted the same in posix paths and file: URLs) will still only work when imported from specific modules. Example:

// Works!
import 'file:///mnt/c/Users/starptech/test.mjs';

// Fails, sometimes!
import '/mnt/c/Users/starptech/test.mjs';

The second import would fail if the module above was loaded from a data: URL. Or really: From any URL that isn't a local file URL. Unless the author really knows what they're doing, I would highly recommend including the protocol for file URLs and not flipping that coin.

If it can't be guaranteed, from a design perspective the API is prone to errors. Why we don't enforce the file: protocol for absolute paths?

@StarpTech i don't understand what you want to enforce, can you clarify? right now https://url.spec.whatwg.org/#relative-url-string is what is being followed to https://url.spec.whatwg.org/#path-absolute-url-string .

One other option we can consider here would be to improve the error message in the case of an absolute windows path.

The problem here is that I had absolutely not clue on why some code I wrote was not working on windows as the code was working smoothly on Linux and Mac. The developer experience for this was far from great, because the only way to debug this would be to have a Windows machine

One other option we can consider here would be to improve the error message in the case of an absolute windows path.

I think this would be the bare minimum change that improve the developer experience.

We could also just make the paths not work on Linux or Mac. That seems odd though and would remove some URL support.

I think improving the error message so it is clear is a good first step. If I am mistaken it seems like the issue is manually creating a URL... is the exact same code working on OSX and failing on windows?

@bmeck forget it. I think logging a warning message in case of an absolute URL without a special scheme e.g file:// would be a good hint.

If I am mistaken it seems like the issue is manually creating a URL... is the exact same code working on OSX and failing on windows?

@MylesBorins Yes, it works by the use of url.pathToFileURL.

What I think would be helpful is adding a check in the ERR_UNSUPPORTED_ESM_URL_SCHEME constructor which checks if the url's scheme is a single letter and the system is on windows, and then offering that you probably want to prefix it with file://

/cc @weswigham

Was this page helpful?
0 / 5 - 0 ratings

Related issues

srl295 picture srl295  路  3Comments

addaleax picture addaleax  路  3Comments

mcollina picture mcollina  路  3Comments

cong88 picture cong88  路  3Comments

seishun picture seishun  路  3Comments