diff --git a/lib/internal/errors.js b/lib/internal/errors.js index 13b56311d370b8..366774cea11fca 100644 --- a/lib/internal/errors.js +++ b/lib/internal/errors.js @@ -1396,26 +1396,6 @@ E('ERR_PACKAGE_PATH_NOT_EXPORTED', (pkgPath, subpath, base = undefined) => { E('ERR_PERFORMANCE_INVALID_TIMESTAMP', '%d is not a valid timestamp', TypeError); E('ERR_PERFORMANCE_MEASURE_INVALID_OPTIONS', '%s', TypeError); -E('ERR_REQUIRE_ESM', - (filename, parentPath = null, packageJsonPath = null) => { - let msg = `Must use import to load ES Module: ${filename}`; - if (parentPath && packageJsonPath) { - const path = require('path'); - const basename = path.basename(filename) === path.basename(parentPath) ? - filename : path.basename(filename); - msg += - '\nrequire() of ES modules is not supported.\nrequire() of ' + - `${filename} from ${parentPath} ` + - 'is an ES module file as it is a .js file whose nearest parent ' + - 'package.json contains "type": "module" which defines all .js ' + - 'files in that package scope as ES modules.\nInstead rename ' + - `${basename} to end in .cjs, change the requiring code to use ` + - 'import(), or remove "type": "module" from ' + - `${packageJsonPath}.\n`; - return msg; - } - return msg; - }, Error); E('ERR_SCRIPT_EXECUTION_INTERRUPTED', 'Script execution was interrupted by `SIGINT`', Error); E('ERR_SERVER_ALREADY_LISTEN', diff --git a/lib/internal/modules/cjs/loader.js b/lib/internal/modules/cjs/loader.js index 4f2b594755262f..79dd1beabb98c9 100644 --- a/lib/internal/modules/cjs/loader.js +++ b/lib/internal/modules/cjs/loader.js @@ -111,7 +111,6 @@ let hasLoadedAnyUserCJSModule = false; const { ERR_INVALID_ARG_VALUE, ERR_INVALID_MODULE_SPECIFIER, - ERR_REQUIRE_ESM, ERR_UNKNOWN_BUILTIN_MODULE, } = require('internal/errors').codes; const { validateString } = require('internal/validators'); @@ -983,8 +982,17 @@ Module.prototype.load = function(filename) { const extension = findLongestRegisteredExtension(filename); // allow .mjs to be overridden - if (StringPrototypeEndsWith(filename, '.mjs') && !Module._extensions['.mjs']) - throw new ERR_REQUIRE_ESM(filename); + if (StringPrototypeEndsWith(filename, '.mjs') && + !Module._extensions['.mjs']) { + process.emitWarning('Attempting to require and ESModule.' + + 'Replace `require` with `import`', + 'Warning', 'WARN_REQUIRE_ESM'); + const ESMLoader = asyncESM.ESMLoader; + const exports = ESMLoader.import(filename); + this.exports = exports; + this.loaded = true; + return; + } Module._extensions[extension](this, filename); this.loaded = true; @@ -1120,10 +1128,14 @@ Module._extensions['.js'] = function(module, filename) { const pkg = readPackageScope(filename); // Function require shouldn't be used in ES modules. if (pkg?.data?.type === 'module') { - const parent = moduleParentCache.get(module); - const parentPath = parent?.filename; - const packageJsonPath = path.resolve(pkg.path, 'package.json'); - throw new ERR_REQUIRE_ESM(filename, parentPath, packageJsonPath); + process.emitWarning('Attempting to require and ESModule.' + + 'Replace `require` with `import`', + 'Warning', 'WARN_REQUIRE_ESM'); + const ESMLoader = asyncESM.ESMLoader; + const exports = ESMLoader.import(filename); + module.exports = exports; + module.loaded = true; + return; } } // If already analyzed the source, then it will be cached. diff --git a/test/es-module/test-cjs-esm-warn.js b/test/es-module/test-cjs-esm-warn.js deleted file mode 100644 index ddeda72fc84b41..00000000000000 --- a/test/es-module/test-cjs-esm-warn.js +++ /dev/null @@ -1,41 +0,0 @@ -'use strict'; - -const common = require('../common'); -const fixtures = require('../common/fixtures'); -const { spawn } = require('child_process'); -const assert = require('assert'); -const path = require('path'); - -const requiring = path.resolve(fixtures.path('/es-modules/cjs-esm.js')); -const required = path.resolve( - fixtures.path('/es-modules/package-type-module/cjs.js') -); -const pjson = path.resolve( - fixtures.path('/es-modules/package-type-module/package.json') -); - -const basename = 'cjs.js'; - -const child = spawn(process.execPath, [requiring]); -let stderr = ''; -child.stderr.setEncoding('utf8'); -child.stderr.on('data', (data) => { - stderr += data; -}); -child.on('close', common.mustCall((code, signal) => { - assert.strictEqual(code, 1); - assert.strictEqual(signal, null); - - assert.ok(stderr.replace(/\r/g, '').includes( - `Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: ${required}` + - '\nrequire() of ES modules is not supported.\nrequire() of ' + - `${required} from ${requiring} ` + - 'is an ES module file as it is a .js file whose nearest parent ' + - 'package.json contains "type": "module" which defines all .js ' + - 'files in that package scope as ES modules.\nInstead rename ' + - `${basename} to end in .cjs, change the requiring code to use ` + - 'import(), or remove "type": "module" from ' + - `${pjson}.\n`)); - assert.ok(stderr.includes( - 'Error [ERR_REQUIRE_ESM]: Must use import to load ES Module')); -})); diff --git a/test/es-module/test-esm-type-flag-errors.js b/test/es-module/test-esm-type-flag-errors.js index e0dedc16cabf8c..e05ee9ee9507dc 100644 --- a/test/es-module/test-esm-type-flag-errors.js +++ b/test/es-module/test-esm-type-flag-errors.js @@ -23,16 +23,6 @@ expect('', packageWithoutTypeMain, 'package-without-type'); expect('--input-type=module', packageTypeModuleMain, 'ERR_INPUT_TYPE_NOT_ALLOWED', true); -try { - require('../fixtures/es-modules/package-type-module/index.js'); - assert.fail('Expected CJS to fail loading from type: module package.'); -} catch (e) { - assert.strictEqual(e.name, 'Error'); - assert.strictEqual(e.code, 'ERR_REQUIRE_ESM'); - assert(e.toString().match(/Must use import to load ES Module/g)); - assert(e.message.match(/Must use import to load ES Module/g)); -} - function expect(opt = '', inputFile, want, wantsError = false) { const argv = [inputFile]; const opts = { diff --git a/test/parallel/test-require-mjs.js b/test/parallel/test-require-mjs.js index 69f8527555db71..a65a165cfe0c18 100644 --- a/test/parallel/test-require-mjs.js +++ b/test/parallel/test-require-mjs.js @@ -1,11 +1,22 @@ 'use strict'; -require('../common'); +const { expectWarning } = require('../common'); const assert = require('assert'); -assert.throws( - () => require('../fixtures/es-modules/test-esm-ok.mjs'), - { - message: /Must use import to load ES Module/, - code: 'ERR_REQUIRE_ESM' - } -); +expectWarning('Warning', [ + [ + 'Attempting to require and ESModule. Replace `require` with `import`', + 'WARN_REQUIRE_ESM', + ], + [ + 'Attempting to require and ESModule. Replace `require` with `import`', + 'WARN_REQUIRE_ESM', + ], +]); + +require('../fixtures/es-modules/test-esm-ok.mjs').then((module) => { + assert.ok(module.default); +}); + +require('../fixtures/es-modules/package-type-module').then((module) => { + assert.strictEqual(module.default, 'package-type-module'); +});