Skip to content
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

v14 regresses #16605: node --experimental-modules does not allow running files without an extension #33259

Closed
jeffs opened this issue May 5, 2020 · 9 comments

Comments

@jeffs
Copy link

jeffs commented May 5, 2020

What steps will reproduce the bug?

~ $ mkdir my-project && cd my-project

my-project $ npm init -y >/dev/null

my-project $ jq '. + { type: "module" }' package.json > a && mv a package.json

my-project $ echo "console.log('hi');" > lib.js

my-project $ echo "import './lib.js';" > main

my-project $ nvm use 12 && node --experimental-modules --no-warnings main
Now using node v12.14.0 (npm v6.14.5)
hi

my-project $ nvm use 14 && node --experimental-modules --no-warnings main
Now using node v14.2.0 (npm v6.14.4)
internal/modules/run_main.js:54
    internalBinding('errors').triggerUncaughtException(
                              ^

TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension "" for /home/jeff/my-project/main
    at Loader.defaultGetFormat [as _getFormat] (internal/modules/esm/get_format.js:65:15)
    at Loader.getFormat (internal/modules/esm/loader.js:113:42)
    at Loader.getModuleJob (internal/modules/esm/loader.js:244:31)
    at async Loader.import (internal/modules/esm/loader.js:178:17) {
  code: 'ERR_UNKNOWN_FILE_EXTENSION'
}

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

Seems pretty reliable.

What is the expected behavior?

Node should interpret a specified file, even if it has no extension.

What do you see instead?

Node throws if the specified file has no extension.

@guybedford
Copy link
Contributor

@jeffs this is correct - files without an extension are disallowed under "type": "module". I would still like to revert that change personally for the main entry point, but it's a tricky consensus issue.

@guybedford
Copy link
Contributor

This is not strictly a regression though since "type": "module" is new behaviour in terms of its semantics.

@jeffs
Copy link
Author

jeffs commented May 5, 2020

Thanks Guy, but I'm not sure what you mean. "type: "module was already supported in v12, and the behavior has now changed in a backward-incompatible way. That seems like the definition of a regression to me. Am I missing some subtlety of the vocabulary? Are you saying the breakage is deliberate, and therefore not considered a regression by the implementers?

Are you aware of any work-around? I'd really like to not have to add a separate platform-specific shell script to wrap every Node program. I'm happy to help with implementation or consensus-building if I can.

@guybedford
Copy link
Contributor

Don't use "type": "module" if you need an extensionless file to run.

It's not strictly a regression because modules semantics are experimental and unstable.

I would like to see if we can change this still... just summoning the energy for it.

@jeffs
Copy link
Author

jeffs commented May 5, 2020

I see, thanks for explaining. Fair enough: Any feature with "experimental" right in the name is bound to change.

Node seems to respect the flag --input-type=module even when the input comes from a file, though the docs only mention it for strings. That's good enough for me. I stand corrected; user error.

Re. energy: Ping me if I can buy you a coffee or a Red Bull. I agree that this change is bad: It's likely to cause a lot more pain than it avoids.

@jeffs jeffs closed this as completed May 5, 2020
@jeffs
Copy link
Author

jeffs commented May 5, 2020

D'oh, --input-type throws if and only if (!) the file contains an import statement. Please do let the world know if you discover any work-around.

@adrian-branescu
Copy link

adrian-branescu commented May 20, 2020

Same issue when --experimental-loader is used. It replicates in both v14.2.0 & v14.3.0.

I've tried also enabling --experimental-specifier-resolution=node but, instead of fixing the missing extension problem, it throws another error.

internal/modules/run_main.js:54
    internalBinding('errors').triggerUncaughtException(
                              ^

TypeError [ERR_INVALID_RETURN_PROPERTY_VALUE]: Expected string to be returned for the "format" from the "loader getFormat" function but got type object.
    at Loader.getFormat (internal/modules/esm/loader.js:122:13)
    at async Loader.getModuleJob (internal/modules/esm/loader.js:243:20)
    at async Loader.import (internal/modules/esm/loader.js:177:17) {
  code: 'ERR_INVALID_RETURN_PROPERTY_VALUE'
}

Should I overwrite also the https://nodejs.org/api/esm.html#esm_code_getformat_code_hook in my loader to return { format: 'commonjs' } for extension-less urls (that doesn't start with nodejs: prefix, e.g. nodejs:events)?

@mrsufgi
Copy link

mrsufgi commented Aug 9, 2020

@adrian-branescu when adding --experimental-specifier-resolution=node without and custom loader (ts-node/esm) it breaks with Expected string to be returned for the "format" from the "loader getFormat" function but got type object.
Our output file extension is .js so it happens even for files with extensions :(

ahbnr added a commit to tdelta/SynergyQuest that referenced this issue Oct 25, 2020
See also
nodejs/node#33259 (comment)

Fixed by switching to CommonJS modules instead of esnext
@ahummel25
Copy link

@mrsufgi Getting the same exact issue. Did you happen to find a workaround for it?

ahbnr added a commit to tdelta/SynergyQuest that referenced this issue Apr 1, 2021
See also
nodejs/node#33259 (comment)

Fixed by switching to CommonJS modules instead of esnext
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants