Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

esm: refine ERR_REQUIRE_ESM errors #39175

Closed
wants to merge 17 commits into from

Conversation

guybedford
Copy link
Contributor

@guybedford guybedford commented Jun 27, 2021

This PR attempts to improve the usability of the ERR_REQUIRE_ESM error messages with two major improvements:

  1. When the module being required contains parseable ESM syntax, constrain the suggested fix to the message "Instead change the require of X.js in Y.js to a dynamic import() which is available in all CommonJS modules." which avoids confusion since we currently suggest all three of that plus changing the type and the extension to cjs, both of which are not appropriate in this case. This is implemented by using the acorn parser on the source at error time.
  2. Ensure that the error mesage frame points to the exact location of the require. This was quite a bit of work to implement and involved a new primitive for exposing the arrow_message_private_symbol to JS so that JS code can inject this frame. The code to reconstruct the frame is more custom than it should be - ideally this could use the standard stack trace API with full source maps integration and be customizable in a way that fits with the stack trace overrides. I hope we can continue to improve this primitives over time to get better error messages more easily in Node.js.

In addition the internal frames are stripped from the error stack to remove the redundant internal stack lines to ensure that the output is as simple as possible for this error message.

I've provided two examples below. One for requiring CJS that Node.js thinks is ESM, and one requiring ESM that actually contains import / export syntax.

Requiring ESM with ESM syntax Before this PR:

internal/modules/cjs/loader.js:1080
      throw new ERR_REQUIRE_ESM(filename, parentPath, packageJsonPath);
      ^

Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: /home/guybedford/Projects/node/test.js
require() of ES modules is not supported.
require() of /home/guybedford/Projects/node/test.js from /home/guybedford/Projects/node/test.cjs 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.
Instead rename test.js to end in .cjs, change the requiring code to use import(), or change "type": "module" to "type": "commonjs" in /home/guybedford/Projects/node/package.json to treat all .js files as CommonJS (using .mjs for all ES modules instead).

    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1080:13)
    at Module.load (internal/modules/cjs/loader.js:928:32)
    at Function.Module._load (internal/modules/cjs/loader.js:769:14)
    at Module.require (internal/modules/cjs/loader.js:952:19)
    at require (internal/modules/cjs/helpers.js:88:18)
    at Object.<anonymous> (/home/guybedford/Projects/node/test.cjs:1:1)
    at Module._compile (internal/modules/cjs/loader.js:1063:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1092:10)
    at Module.load (internal/modules/cjs/loader.js:928:32)
    at Function.Module._load (internal/modules/cjs/loader.js:769:14) {
  code: 'ERR_REQUIRE_ESM'
}

Requiring ESM with ESM syntax after this PR:

/home/guybedford/Projects/node/test.cjs:1
require('./test.js');
^

Error [ERR_REQUIRE_ESM]: require() of ES Module /home/guybedford/Projects/node/test.js from /home/guybedford/Projects/node/test.cjs not supported.
Instead change the require of test.js in /home/guybedford/Projects/node/test.cjs to a dynamic import() which is available in all CommonJS modules.
    at Object.<anonymous> (/home/guybedford/Projects/node/test.cjs:1:1) {
  code: 'ERR_REQUIRE_ESM'
}

Requiring a .js file with no import or export syntax before this PR:

internal/modules/cjs/loader.js:1080
      throw new ERR_REQUIRE_ESM(filename, parentPath, packageJsonPath);
      ^

Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: /home/guybedford/Projects/node/test.js
require() of ES modules is not supported.
require() of /home/guybedford/Projects/node/test.js from /home/guybedford/Projects/node/test.cjs 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.
Instead rename test.js to end in .cjs, change the requiring code to use import(), or change "type": "module" to "type": "commonjs" in /home/guybedford/Projects/node/package.json to treat all .js files as CommonJS (using .mjs for all ES modules instead).

    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1080:13)
    at Module.load (internal/modules/cjs/loader.js:928:32)
    at Function.Module._load (internal/modules/cjs/loader.js:769:14)
    at Module.require (internal/modules/cjs/loader.js:952:19)
    at require (internal/modules/cjs/helpers.js:88:18)
    at Object.<anonymous> (/home/guybedford/Projects/node/test.cjs:1:1)
    at Module._compile (internal/modules/cjs/loader.js:1063:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1092:10)
    at Module.load (internal/modules/cjs/loader.js:928:32)
    at Function.Module._load (internal/modules/cjs/loader.js:769:14) {
  code: 'ERR_REQUIRE_ESM'
}

Requiring a .js file with no import or export syntax after this PR:

/home/guybedford/Projects/node/test.cjs:1
require('./test.js');
^

Error [ERR_REQUIRE_ESM]: require() of ES Module /home/guybedford/Projects/node/test.js from /home/guybedford/Projects/node/test.cjs not supported.
test.js is treated as an ES module file as it is a .js file whose nearest parent package.json contains "type": "module" which declares all .js files in that package scope as ES modules.
Instead rename test.js to end in .cjs, change the requiring code to use dynamic import() which is available in all CommonJS modules, or change "type": "module" to "type": "commonjs" in /home/guybedford/Projects/node/package.json to treat all .js files as CommonJS (using .mjs for all ES modules instead).

    at Object.<anonymous> (/home/guybedford/Projects/node/test.cjs:1:1) {
  code: 'ERR_REQUIRE_ESM'
}

Requiring a .mjs file before this PR:

internal/modules/cjs/loader.js:926
    throw new ERR_REQUIRE_ESM(filename);
    ^

Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: /home/guybedford/Projects/node/test.mjs
    at Module.load (internal/modules/cjs/loader.js:926:11)
    at Function.Module._load (internal/modules/cjs/loader.js:769:14)
    at Module.require (internal/modules/cjs/loader.js:952:19)
    at require (internal/modules/cjs/helpers.js:88:18)
    at Object.<anonymous> (/home/guybedford/Projects/node/test.cjs:1:1)
    at Module._compile (internal/modules/cjs/loader.js:1063:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1092:10)
    at Module.load (internal/modules/cjs/loader.js:928:32)
    at Function.Module._load (internal/modules/cjs/loader.js:769:14)
    at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:72:12) {
  code: 'ERR_REQUIRE_ESM'
}

Requiring a .mjs file after this PR:

node:internal/modules/cjs/loader:978
    throw new ERR_REQUIRE_ESM(filename, true);
    ^

Error [ERR_REQUIRE_ESM]: require() of ES Module /home/guybedford/Projects/node/test.mjs not supported.
Instead change the require of /home/guybedford/Projects/node/test.mjs to a dynamic import() which is available in all CommonJS modules.
    at Object.<anonymous> (/home/guybedford/Projects/node/test.cjs:1:1) {
  code: 'ERR_REQUIRE_ESM'
}

@nodejs/modules

@github-actions github-actions bot added c++ Issues and PRs that require attention from people who are familiar with C++. errors Issues and PRs related to JavaScript errors originated in Node.js core. needs-ci PRs that need a full CI run. labels Jun 27, 2021
@guybedford
Copy link
Contributor Author

@GeoffreyBooth I know we went through this many times before, but since it keeps coming up I'm happy to go through the same discussions again on the exact wording.

lib/internal/errors.js Outdated Show resolved Hide resolved
lib/internal/errors.js Outdated Show resolved Hide resolved
lib/internal/errors.js Outdated Show resolved Hide resolved
lib/internal/errors.js Outdated Show resolved Hide resolved
lib/internal/modules/cjs/helpers.js Outdated Show resolved Hide resolved
lib/internal/errors.js Outdated Show resolved Hide resolved
// Hide stack lines before the first user code line.
function hideLeadingInternalFrames(error, stackFrames) {
let frames = stackFrames;
if (typeof stackFrames === 'object') {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: %Array.isArray% would be more readable (or maybe stackFrames !== undefined would be enough?).

Suggested change
if (typeof stackFrames === 'object') {
if (ArrayIsArray(stackFrames)) {

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This came from a line of code in repl written by @devsnek. Wasn't sure if there was some original reason for it.

lib/internal/errors.js Outdated Show resolved Hide resolved
lib/internal/modules/cjs/helpers.js Outdated Show resolved Hide resolved
src/node_errors.cc Outdated Show resolved Hide resolved
@devsnek
Copy link
Member

devsnek commented Jul 8, 2021

now that my pr landed, you can remove deferStack, overrideStackTraceByCode, etc., and just put the error in the overrideStackTrace map.

@guybedford
Copy link
Contributor Author

@devsnek working great - I've pushed that up.

@guybedford guybedford dismissed devsnek’s stale review July 8, 2021 17:53

Feedback merged in separate PR.

@guybedford
Copy link
Contributor Author

Ping @nodejs/modules for further reviewers on the error message improvements here.

Copy link
Member

@bmeck bmeck left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems fine to me, there are cheaper top level parsers, but since we are on an error path, this seems fine.

@@ -788,6 +789,34 @@ const fatalExceptionStackEnhancers = {
}
};

// Ensures the printed error line is from user code.
let _kArrowMessagePrivateSymbol, _setHiddenValue;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do they have to be lazy?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They don't have to be, but we only hit this path on ERR_REQUIRE_ESM errors. I was following the pattern of other lazy requires used in this module.

test/es-module/test-cjs-esm-warn.js Outdated Show resolved Hide resolved
test/es-module/test-cjs-esm-warn.js Outdated Show resolved Hide resolved
lib/internal/modules/cjs/loader.js Outdated Show resolved Hide resolved
lib/internal/modules/cjs/loader.js Outdated Show resolved Hide resolved
@nodejs-github-bot

This comment has been minimized.

@nodejs-github-bot

This comment has been minimized.

@nodejs-github-bot

This comment has been minimized.

@nodejs-github-bot
Copy link
Collaborator

guybedford added a commit that referenced this pull request Jul 15, 2021
PR-URL: #39175
Reviewed-By: Bradley Farias <bradley.meck@gmail.com>
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
@guybedford
Copy link
Contributor Author

Landed in e2a6399.

@guybedford guybedford closed this Jul 15, 2021
@guybedford guybedford deleted the require-esm-improvements branch July 15, 2021 15:52
targos pushed a commit that referenced this pull request Jul 17, 2021
PR-URL: #39175
Reviewed-By: Bradley Farias <bradley.meck@gmail.com>
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
@BethGriggs BethGriggs mentioned this pull request Jul 26, 2021
BethGriggs pushed a commit that referenced this pull request Jul 29, 2021
PR-URL: #39175
Reviewed-By: Bradley Farias <bradley.meck@gmail.com>
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
olizilla added a commit to web3-storage/web3.storage that referenced this pull request Jul 30, 2021
since node 16.6 webpack-cli fails to load esm config unless WEBPACK_CLI_FORCE_LOAD_ESM_CONFIG=true

see: nodejs/node#39175
see: https://github.com/webpack/webpack-cli/blob/a660ffcbeb2807bce1554f787297e697464abd59/packages/webpack-cli/lib/webpack-cli.js#L50-L51

License: (Apache-2.0 AND MIT)
Signed-off-by: Oli Evans <oli@tableflip.io>
olizilla added a commit to web3-storage/web3.storage that referenced this pull request Jul 30, 2021
Since node v16.6 webpack-cli fails to load esm config unless WEBPACK_CLI_FORCE_LOAD_ESM_CONFIG=true

see: nodejs/node#39175
see: https://github.com/webpack/webpack-cli/blob/a660ffcbeb2807bce1554f787297e697464abd59/packages/webpack-cli/lib/webpack-cli.js#L50-L51


License: (Apache-2.0 AND MIT)
Signed-off-by: Oli Evans <oli@tableflip.io>
johndmulhausen pushed a commit to web3-storage/web3.storage that referenced this pull request Aug 6, 2021
Since node v16.6 webpack-cli fails to load esm config unless WEBPACK_CLI_FORCE_LOAD_ESM_CONFIG=true

see: nodejs/node#39175
see: https://github.com/webpack/webpack-cli/blob/a660ffcbeb2807bce1554f787297e697464abd59/packages/webpack-cli/lib/webpack-cli.js#L50-L51


License: (Apache-2.0 AND MIT)
Signed-off-by: Oli Evans <oli@tableflip.io>
danielcompton added a commit to danielcompton/node that referenced this pull request Sep 6, 2023
In nodejs#39175, better ESM errors were introduced. This commit tweaks the
language in the error slightly to make it clear that there are three
different options to resolve the error.
danielcompton added a commit to danielcompton/node that referenced this pull request Sep 6, 2023
In nodejs#39175, better ESM errors were introduced. This commit tweaks the
language in the error slightly to make it clear that there are three
different options to resolve the error.

Refs: nodejs#39175
nodejs-github-bot pushed a commit that referenced this pull request Sep 15, 2023
In #39175, better ESM errors were introduced. This commit tweaks the
language in the error slightly to make it clear that there are three
different options to resolve the error.

Refs: #39175
PR-URL: #49521
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: Jacob Smith <jacob@frende.me>
Reviewed-By: Geoffrey Booth <webadmin@geoffreybooth.com>
Reviewed-By: Stephen Belanger <admin@stephenbelanger.com>
ruyadorno pushed a commit that referenced this pull request Sep 28, 2023
In #39175, better ESM errors were introduced. This commit tweaks the
language in the error slightly to make it clear that there are three
different options to resolve the error.

Refs: #39175
PR-URL: #49521
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: Jacob Smith <jacob@frende.me>
Reviewed-By: Geoffrey Booth <webadmin@geoffreybooth.com>
Reviewed-By: Stephen Belanger <admin@stephenbelanger.com>
alexfernandez pushed a commit to alexfernandez/node that referenced this pull request Nov 1, 2023
In nodejs#39175, better ESM errors were introduced. This commit tweaks the
language in the error slightly to make it clear that there are three
different options to resolve the error.

Refs: nodejs#39175
PR-URL: nodejs#49521
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: Jacob Smith <jacob@frende.me>
Reviewed-By: Geoffrey Booth <webadmin@geoffreybooth.com>
Reviewed-By: Stephen Belanger <admin@stephenbelanger.com>
targos pushed a commit to targos/node that referenced this pull request Nov 11, 2023
In nodejs#39175, better ESM errors were introduced. This commit tweaks the
language in the error slightly to make it clear that there are three
different options to resolve the error.

Refs: nodejs#39175
PR-URL: nodejs#49521
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: Jacob Smith <jacob@frende.me>
Reviewed-By: Geoffrey Booth <webadmin@geoffreybooth.com>
Reviewed-By: Stephen Belanger <admin@stephenbelanger.com>
targos pushed a commit that referenced this pull request Nov 23, 2023
In #39175, better ESM errors were introduced. This commit tweaks the
language in the error slightly to make it clear that there are three
different options to resolve the error.

Refs: #39175
PR-URL: #49521
Backport-PR-URL: #50669
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: Jacob Smith <jacob@frende.me>
Reviewed-By: Geoffrey Booth <webadmin@geoffreybooth.com>
Reviewed-By: Stephen Belanger <admin@stephenbelanger.com>
sercher added a commit to sercher/graaljs that referenced this pull request Apr 25, 2024
In #39175, better ESM errors were introduced. This commit tweaks the
language in the error slightly to make it clear that there are three
different options to resolve the error.

Refs: nodejs/node#39175
PR-URL: nodejs/node#49521
Backport-PR-URL: nodejs/node#50669
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: Jacob Smith <jacob@frende.me>
Reviewed-By: Geoffrey Booth <webadmin@geoffreybooth.com>
Reviewed-By: Stephen Belanger <admin@stephenbelanger.com>
sercher added a commit to sercher/graaljs that referenced this pull request Apr 25, 2024
In #39175, better ESM errors were introduced. This commit tweaks the
language in the error slightly to make it clear that there are three
different options to resolve the error.

Refs: nodejs/node#39175
PR-URL: nodejs/node#49521
Backport-PR-URL: nodejs/node#50669
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: Jacob Smith <jacob@frende.me>
Reviewed-By: Geoffrey Booth <webadmin@geoffreybooth.com>
Reviewed-By: Stephen Belanger <admin@stephenbelanger.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
c++ Issues and PRs that require attention from people who are familiar with C++. errors Issues and PRs related to JavaScript errors originated in Node.js core. needs-ci PRs that need a full CI run.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

10 participants