What is the problem this feature will solve?
I thought that the --experimental-specifier-resolution=node CLI option was made to emulate legacy cjs resolution algorithm. However the legacy cjs module loader can handle extension-less files whereas which is not the case with this CLI option:
> cat yo
console.log("yo");
> node yo
yo
> node --experimental-specifier-resolution=node yo
(node:33081) ExperimentalWarning: The Node.js specifier resolution in ESM is experimental.
(Use `node --trace-warnings ...` to show where the warning was created)
node:internal/errors:464
ErrorCaptureStackTrace(err);
^
TypeError [ERR_INVALID_MODULE_SPECIFIER]: Invalid module "file:///Users/soft/Desktop/workspace/appmap-agent-js/yo"
at new NodeError (node:internal/errors:371:5)
at ESMLoader.load (node:internal/modules/esm/loader:380:13)
at async ESMLoader.moduleProvider (node:internal/modules/esm/loader:280:47)
at async link (node:internal/modules/esm/module_job:70:21) {
code: 'ERR_INVALID_MODULE_SPECIFIER'
}
Node.js v17.3.0
These extension-less files are actually common in the bin directory of many popular projects -- eg: mocha. This makes it hard to use --experimental-loader on these projects because the below command fails for the same reason as above:
NODE_OPTIONS="--experimental-loader=./loader.mjs --experimental-specifier-resolution=node" npx mocha
What is the feature you are proposing to solve the problem?
Consider extension-less files as commonjs modules as the legacy cjs loader does. This is can done be done easily by modifying legacyExtensionFormatMap in lib/internal/modules/esm/get_format.js:
const legacyExtensionFormatMap = {
'__proto__': null,
'.cjs': 'commonjs',
'.js': 'commonjs',
'.json': 'commonjs',
'.mjs': 'module',
'.node': 'commonjs',
'': 'commonjs' // Added line
};
Is there a good reason why this has not been considered?
What alternatives have you considered?
- Resolve the module in the loader provided by
--experimental-loader and do not pass it to the default loader. This is a bazooka solution because the loader API basically enables to write one's own module resolution algorithm. We don't want to emulate the entire module resolution algorithm for such a minimal change.
- Rename and change the target of the symbolic link installed by npm to add a
.js extension. This must happen in a preloaded module. It is extremely hacky and does not work on windows.
What is the problem this feature will solve?
I thought that the
--experimental-specifier-resolution=nodeCLI option was made to emulate legacy cjs resolution algorithm. However the legacy cjs module loader can handle extension-less files whereas which is not the case with this CLI option:> cat yo console.log("yo"); > node yo yo > node --experimental-specifier-resolution=node yo (node:33081) ExperimentalWarning: The Node.js specifier resolution in ESM is experimental. (Use `node --trace-warnings ...` to show where the warning was created) node:internal/errors:464 ErrorCaptureStackTrace(err); ^ TypeError [ERR_INVALID_MODULE_SPECIFIER]: Invalid module "file:///Users/soft/Desktop/workspace/appmap-agent-js/yo" at new NodeError (node:internal/errors:371:5) at ESMLoader.load (node:internal/modules/esm/loader:380:13) at async ESMLoader.moduleProvider (node:internal/modules/esm/loader:280:47) at async link (node:internal/modules/esm/module_job:70:21) { code: 'ERR_INVALID_MODULE_SPECIFIER' } Node.js v17.3.0These extension-less files are actually common in the
bindirectory of many popular projects -- eg: mocha. This makes it hard to use--experimental-loaderon these projects because the below command fails for the same reason as above:NODE_OPTIONS="--experimental-loader=./loader.mjs --experimental-specifier-resolution=node" npx mochaWhat is the feature you are proposing to solve the problem?
Consider extension-less files as commonjs modules as the legacy cjs loader does. This is can done be done easily by modifying
legacyExtensionFormatMapin lib/internal/modules/esm/get_format.js:Is there a good reason why this has not been considered?
What alternatives have you considered?
--experimental-loaderand do not pass it to the default loader. This is a bazooka solution because the loader API basically enables to write one's own module resolution algorithm. We don't want to emulate the entire module resolution algorithm for such a minimal change..jsextension. This must happen in a preloaded module. It is extremely hacky and does not work on windows.