Skip to content

Commit

Permalink
module: check --experimental-require-module separately from detection
Browse files Browse the repository at this point in the history
Previously we assumed if `--experimental-detect-module` is true, then
`--experimental-require-module` is true, which isn't the case, as
the two can be enabled/disabled separately. This patch fixes the
checks so `--no-experimental-require-module` is still effective when
`--experimental-detect-module` is enabled.

Drive-by: make the assertion messages more informative and remove
obsolete TODO about allowing TLA in entrypoints handled by
require(esm).

PR-URL: nodejs#55250
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: Jacob Smith <jacob@frende.me>
Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com>
  • Loading branch information
joyeecheung committed Nov 12, 2024
1 parent d20718f commit 6d279be
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 5 deletions.
16 changes: 12 additions & 4 deletions lib/internal/modules/cjs/loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -1438,7 +1438,7 @@ function loadESMFromCJS(mod, filename) {
* @param {'commonjs'|undefined} format Intended format of the module.
*/
function wrapSafe(filename, content, cjsModuleInstance, format) {
assert(format !== 'module'); // ESM should be handled in loadESMFromCJS().
assert(format !== 'module', 'ESM should be handled in loadESMFromCJS()');
const hostDefinedOptionId = vm_dynamic_import_default_internal;
const importModuleDynamically = vm_dynamic_import_default_internal;
if (patched) {
Expand Down Expand Up @@ -1468,7 +1468,17 @@ function wrapSafe(filename, content, cjsModuleInstance, format) {
};
}

const shouldDetectModule = (format !== 'commonjs' && getOptionValue('--experimental-detect-module'));
let shouldDetectModule = false;
if (format !== 'commonjs') {
if (cjsModuleInstance?.[kIsMainSymbol]) {
// For entry points, format detection is used unless explicitly disabled.
shouldDetectModule = getOptionValue('--experimental-detect-module');
} else {
// For modules being loaded by `require()`, if require(esm) is disabled,
// don't try to reparse to detect format and just throw for ESM syntax.
shouldDetectModule = getOptionValue('--experimental-require-module');
}
}
const result = compileFunctionForCJSLoader(content, filename, false /* is_sea_main */, shouldDetectModule);

// Cache the source map for the module if present.
Expand Down Expand Up @@ -1498,8 +1508,6 @@ Module.prototype._compile = function(content, filename, format) {
}
}

// TODO(joyeecheung): when the module is the entry point, consider allowing TLA.
// Only modules being require()'d really need to avoid TLA.
if (format === 'module') {
// Pass the source into the .mjs extension handler indirectly through the cache.
this[kModuleSource] = content;
Expand Down
19 changes: 19 additions & 0 deletions test/es-module/test-disable-require-module-with-detection.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Flags: --no-experimental-require-module
'use strict';

// Tests that --experimental-require-module is not implied by --experimental-detect-module
// and is checked independently.
require('../common');
const assert = require('assert');

// Check that require() still throws SyntaxError for an ambiguous module that's detected to be ESM.
// TODO(joyeecheung): now that --experimental-detect-module is unflagged, it makes more sense
// to either throw ERR_REQUIRE_ESM for require() of detected ESM instead, or add a hint about the
// use of require(esm) to the SyntaxError.

assert.throws(
() => require('../fixtures/es-modules/loose.js'),
{
name: 'SyntaxError',
message: /Unexpected token 'export'/
});
4 changes: 3 additions & 1 deletion test/fixtures/es-modules/loose.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// This file can be run or imported only if `--experimental-default-type=module` is set.
// This file can be run or imported only if `--experimental-default-type=module` is set
// or `--experimental-detect-module` is not disabled. If it's loaded by
// require(), then `--experimental-require-module` must not be disabled.
export default 'module';
console.log('executed');

0 comments on commit 6d279be

Please sign in to comment.