Skip to content

Commit

Permalink
module: clarify CJS global-like variables not defined error message
Browse files Browse the repository at this point in the history
Fixes: #33741
  • Loading branch information
aduh95 committed Mar 21, 2021
1 parent 5318e53 commit 5a26936
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 1 deletion.
41 changes: 40 additions & 1 deletion lib/internal/modules/esm/module_job.js
Expand Up @@ -4,6 +4,7 @@ const {
ArrayPrototypeJoin,
ArrayPrototypeMap,
ArrayPrototypePush,
ArrayPrototypeSome,
FunctionPrototype,
ObjectSetPrototypeOf,
PromiseAll,
Expand All @@ -12,10 +13,12 @@ const {
ReflectApply,
SafeArrayIterator,
SafeSet,
StringPrototypeEndsWith,
StringPrototypeIncludes,
StringPrototypeMatch,
StringPrototypeReplace,
StringPrototypeSplit,
StringPrototypeStartsWith,
} = primordials;

const { ModuleWrap } = internalBinding('module_wrap');
Expand All @@ -28,6 +31,19 @@ const noop = FunctionPrototype;

let hasPausedEntry = false;

const CJSGlobalLike = [
'require',
'module',
'exports',
'__filename',
'__dirname',
];
const isCommonJSGlobalLikeNotDefinedError = (errorMessage) =>
ArrayPrototypeSome(
CJSGlobalLike,
(globalLike) => StringPrototypeStartsWith(errorMessage, globalLike)
);

/* A ModuleJob tracks the loading of a single Module, and the ModuleJobs of
* its dependencies, over time. */
class ModuleJob {
Expand Down Expand Up @@ -151,7 +167,30 @@ class ModuleJob {
await this.instantiate();
const timeout = -1;
const breakOnSigint = false;
await this.module.evaluate(timeout, breakOnSigint);
try {
await this.module.evaluate(timeout, breakOnSigint);
} catch (e) {
if (e.name === 'ReferenceError' &&
StringPrototypeEndsWith(e.message, ' is not defined') &&
isCommonJSGlobalLikeNotDefinedError(e.message)) {
e.message += ' in ES module scope';

if (StringPrototypeStartsWith(e.message, 'require')) {
e.message += '. You can use `await import` instead';
}

if (StringPrototypeEndsWith(this.module.url, '.js') &&
StringPrototypeStartsWith(this.module.url, 'file://')) {
e.message +=
'. It seems you are trying to load a file using `.js` extension ' +
'inside a folder containing a `package.json` that includes ' +
'`"type": "module"`; you need to use the `.cjs` extension to ' +
'load the file as a CommonJS module, or add a `package.json` ' +
'file with ``"type": "commonjs"`.';
}
}
throw e;
}
return { module: this.module };
}
}
Expand Down
28 changes: 28 additions & 0 deletions test/es-module/test-esm-undefined-cjs-global-like-variables.js
@@ -0,0 +1,28 @@
'use strict';
const common = require('../common');
const fixtures = require('../common/fixtures');
const assert = require('assert');

assert.rejects(
import('data:text/javascript,require;'),
// eslint-disable-next-line node-core/no-unescaped-regexp-dot
/use .await import. instead/
).then(common.mustCall());

assert.rejects(
import('data:text/javascript,exports={};'),
// eslint-disable-next-line node-core/no-unescaped-regexp-dot
/^(?!use .await import. instead).*$/
).then(common.mustCall());

assert.rejects(
import('data:text/javascript,require;//.js'),
// eslint-disable-next-line node-core/no-unescaped-regexp-dot
/^(?!It seems you are trying to load a file using `.js` extension).*$/
).then(common.mustCall());

assert.rejects(
import(fixtures.path('/es-modules/package-type-module/cjs.js')),
// eslint-disable-next-line node-core/no-unescaped-regexp-dot
/use the .\.cjs. extension to load the file as a CommonJS module/
).then(common.mustCall());

0 comments on commit 5a26936

Please sign in to comment.