-
-
Notifications
You must be signed in to change notification settings - Fork 35k
[25.x] module: fix extensionless CJS files in type:module packages #62083
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
Open
mcollina
wants to merge
1
commit into
nodejs:v25.x-staging
Choose a base branch
from
mcollina:fix/extensionless-cjs-in-type-module
base: v25.x-staging
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+18
−4
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1952,12 +1952,12 @@ Module._extensions['.js'] = function(module, filename) { | |
| format = 'typescript'; | ||
| } | ||
| } else if (path.extname(filename) === '') { | ||
| // Extensionless files skip the .js suffix check above. When type is explicit, | ||
| // follow it so ESM syntax surfaces as SyntaxError for commonjs instead of | ||
| // silently delegating to ESM. | ||
| // Extensionless files skip the .js suffix check above. When type is commonjs, follow it so ESM | ||
| // syntax surfaces as SyntaxError. For type: module, leave format undefined so our syntax | ||
| // detection handles it (allowing CJS extensionless files in ESM packages). | ||
| pkg = packageJsonReader.getNearestParentPackageJSON(filename); | ||
| const typeFromPjson = pkg?.data?.type; | ||
| if (typeFromPjson === 'commonjs' || typeFromPjson === 'module') { | ||
| if (typeFromPjson === 'commonjs') { | ||
| format = typeFromPjson; | ||
| } | ||
|
Comment on lines
+1960
to
1962
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would it be possible to have extensionless files entirely ignore the package.json "type"? That seems like a more pragmatic approach given that they are designed to exist outside of package boundaries in most "binary execution" use cases. |
||
| } | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| module.exports = { hello: 'world' }; |
3 changes: 3 additions & 0 deletions
3
test/fixtures/es-modules/extensionless-cjs-module/package.json
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| { | ||
| "type": "module" | ||
| } |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does our syntax detection handle it? I think to confirm that it does, this PR also needs a test that requiring an extensionless file with ESM syntax in a
type: modulepackage scope also works.This is also the part that worries me, though: according to our docs, syntax detection happens for
Assuming the comment here does what it claims to do, then this PR is creating a new exception to our docs: syntax detection applies in the above case, and for the string input, and for extensionless files in a
type: modulecontext. I thought we wanted syntax detection to never apply when atypefield was set; that's what the warning we print tells users to add to avoid the performance hit of syntax detection. That's why this PR in general feels like the wrong solution to me.Alternatively if this comment is just wrong and there's no syntax detection involved here, then we should fix this comment (and the PR description).
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this needs to factor in that it's not a new exception, it's still the status quo for v20-v24. #61600 removed the exceptions on v25, and this PR is only partially putting a small part of the exception back to prevent regressions on v25, since that part is documented (but not the others). In v26 the exception will be fully disallowed since it'll have #61600 in full.
Alternatively, if we want to forbid syntax detection entirely, to make it strictly follow the documented exception it should change to
if (typeFromPjson === 'module') format = 'commonjs', but that feels even more wrong and it can only happen on v25....syntax detection is mostly just a mechanics to relax the interpretation of the type field to be less wrong, instead of completely going the opposite of what type field says (which is what got documented) and forbid extensionless ESM when there's type: module (meanwhile, without type in package.json it still allows extensionless ESM since 20).There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we're currently doing any syntax detection for files where the controlling
package.jsonfile has atypefield, that's a bug. That's not documented in the syntax detection section, nor in https://nodejs.org/docs/v25.7.0/api/modules.html#enabling. Thetypefield is supposed to prevent syntax detection, full stop, for all files including extensionless ones. That's why we print this:node/lib/internal/modules/esm/get_format.js
Lines 148 to 150 in 17c76c1
So I'm not sure what exception you're referring to? Are the docs and this warning all wrong and we've been secretly doing syntax detection for extensionless files in
type: modulescopes prior to #61600?Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, or more precisely, we had been ignoring the type field for required extensionless files before 61600 - and still do on v20-v24. We didn't even read the package.json's type field at all for required extensionless files until 61600. That's why I say reverting it is going to make it more wrong.
As it turned out, if the type field is module, treating the required extensionless file as ESM caused a regression from the documented exception, so we have two choices to fix it for 25.
Note that this is unrelated to entry points, and only for required extensionless files.