Title: esm: detect ESM syntax in extensionless files under type:commonjs by scott-memco · Pull Request #61737 · nodejs/node · GitHub
Open Graph Title: esm: detect ESM syntax in extensionless files under type:commonjs by scott-memco · Pull Request #61737 · nodejs/node
X Title: esm: detect ESM syntax in extensionless files under type:commonjs by scott-memco · Pull Request #61737 · nodejs/node
Description: Summary Fixes a silent failure where extensionless files containing ES module syntax produce no output and exit with code 0 when the nearest package.json has "type": "commonjs". This is a common scenario for CLI tools that use shebangs (#!/usr/bin/env node) without a file extension. Reproduction echo '{ "type": "commonjs" }' > package.json printf '#!/usr/bin/env node\nconsole.log("started")\nimport { version } from "node:process"\nconsole.log(version)\n' > script chmod +x script ./script ; echo "exit: $?" # Output: exit: 0 # Expected: either the script runs, or an error is printed Root Cause In lib/internal/modules/esm/get_format.js, getFileProtocolModuleFormat() handles extensionless files (line 159-177). When packageType is 'commonjs', it returns 'commonjs' immediately without checking the file content for ESM syntax (line 164-165). This causes the ESM loader to treat the file as a CJS module, routing it through createCJSModuleWrap in the translators, which wraps the ESM code as CJS — silently producing an empty/non-functional module. Compare with: The 'none' (no type field) case for extensionless files, which does call detectModuleFormat(source, url) at line 176 The .js extension case with no type field, which does call detectModuleFormat(source, url) at line 127 Fix For extensionless files when packageType !== 'none' (i.e., explicitly 'commonjs'), check the source content via detectModuleFormat() before returning the package type. If the file contains ES module syntax, return 'module' so it's loaded correctly. if (packageType !== 'none') { if (source) { const detected = detectModuleFormat(source, url); if (detected === 'module') { return detected; } } return packageType; } This is consistent with how ambiguous files are already handled elsewhere in the same function, and relies on the existing containsModuleSyntax V8 binding (used by detectModuleFormat) which is already enabled by default via --experimental-detect-module. Test test/parallel/test-esm-extensionless-commonjs-type.js — creates an extensionless ESM file in a type: commonjs project, runs it, and asserts it does not silently exit with code 0. Fixes: #61104 Made with Cursor
Open Graph Description: Summary Fixes a silent failure where extensionless files containing ES module syntax produce no output and exit with code 0 when the nearest package.json has "type": "commonjs"....
X Description: Summary Fixes a silent failure where extensionless files containing ES module syntax produce no output and exit with code 0 when the nearest package.json has "type": "com...
Opengraph URL: https://github.com/nodejs/node/pull/61737
X: @github
Domain: github.com
| route-pattern | /:user_id/:repository/pull/:id/files(.:format) |
| route-controller | pull_requests |
| route-action | files |
| fetch-nonce | v2:57966595-afb1-8f6a-1555-54be392361de |
| current-catalog-service-hash | ae870bc5e265a340912cde392f23dad3671a0a881730ffdadd82f2f57d81641b |
| request-id | AC80:2630A2:1108D54:177D089:6A4CA5D9 |
| html-safe-nonce | 81fdd108b11d6fc1091a517530f0a5215c7e04720bc0b1155b7e4dd25ef82378 |
| visitor-payload | eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiJBQzgwOjI2MzBBMjoxMTA4RDU0OjE3N0QwODk6NkE0Q0E1RDkiLCJ2aXNpdG9yX2lkIjoiNDU4MjA5Nzk2NDczODg0ODIxNyIsInJlZ2lvbl9lZGdlIjoiaWFkIiwicmVnaW9uX3JlbmRlciI6ImlhZCJ9 |
| visitor-hmac | b393236726300cbbde2159f300f30a7c40a2c994ac2f6544e0243c74d6cd9ade |
| hovercard-subject-tag | pull_request:3259853768 |
| github-keyboard-shortcuts | repository,pull-request-list,pull-request-conversation,pull-request-files-changed,copilot |
| google-site-verification | Apib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I |
| octolytics-url | https://collector.github.com/github/collect |
| analytics-location | / |
| fb:app_id | 1401488693436528 |
| apple-itunes-app | app-id=1477376905, app-argument=https://github.com/nodejs/node/pull/61737/files |
| twitter:image | https://avatars.githubusercontent.com/u/231007988?s=400&v=4 |
| twitter:card | summary_large_image |
| og:image | https://avatars.githubusercontent.com/u/231007988?s=400&v=4 |
| og:image:alt | Summary Fixes a silent failure where extensionless files containing ES module syntax produce no output and exit with code 0 when the nearest package.json has "type": "commonjs".... |
| og:site_name | GitHub |
| og:type | object |
| hostname | github.com |
| expected-hostname | github.com |
| None | 3d11bb817438277de2a940854450e83a7d32b6aeb5014e9e6b00a6423900251c |
| turbo-cache-control | no-preview |
| diff-view | unified |
| go-import | github.com/nodejs/node git https://github.com/nodejs/node.git |
| octolytics-dimension-user_id | 9950313 |
| octolytics-dimension-user_login | nodejs |
| octolytics-dimension-repository_id | 27193779 |
| octolytics-dimension-repository_nwo | nodejs/node |
| octolytics-dimension-repository_public | true |
| octolytics-dimension-repository_is_fork | false |
| octolytics-dimension-repository_network_root_id | 27193779 |
| octolytics-dimension-repository_network_root_nwo | nodejs/node |
| turbo-body-classes | logged-out env-production page-responsive full-width |
| disable-turbo | true |
| browser-stats-url | https://api.github.com/_private/browser/stats |
| browser-errors-url | https://api.github.com/_private/browser/errors |
| release | ae90d426644ca15e89bacceb72e51f4e9dbf85f7 |
| ui-target | full |
| theme-color | #1e2327 |
| color-scheme | light dark |
Links:
Viewport: width=device-width