Skip to content

Improve error message for replacing require usage with dynamic import #40544

@fabiancook

Description

@fabiancook

Version

17.0.1

Platform

Darwin Fabians-Mac-mini-2.local 19.6.0 Darwin Kernel Version 19.6.0: Tue Jan 12 22:13:05 PST 2021; root:xnu-6153.141.16~1/RELEASE_X86_64 x86_64

Subsystem

No response

What steps will reproduce the bug?

package.json:

{
  "type": "module",
  "dependencies": {
    "node-fetch": "3.0.0"
  }
}

index.js:

const fetch = require("node-fetch");
(async function main() {
  const response = await fetch("https://httpbin.org/get");
  const json = await response.json();
  console.log(json);
})();
$ node index.js
const fetch = require("node-fetch");
              ^

ReferenceError: require is not defined in ES module scope, you can use import instead
This file is being treated as an ES module because it has a '.js' file extension and '/Users/fabian/src/reproduce/package.json' contains "type": "module". To treat it as a CommonJS script, rename it to use the '.cjs' file extension.

Direct replacing of require with import (this is an incorrect assumption after looking at the error):

const fetch = import("node-fetch");
(async function main() {
  const response = await fetch("https://httpbin.org/get");
  const json = await response.json();
  console.log(json);
})();
$ node index.js                                                                                                                                                                                                       
file:///Users/fabian/src/reproduce/index.js:3
  const response = await fetch("https://httpbin.org/get");
                         ^

TypeError: fetch is not a function

How often does it reproduce? Is there a required condition?

No response

What is the expected behavior?

Instead the error could say something that includes that the returned value from import must be awaited:

ReferenceError: require is not defined in ES module scope, you can use "const { default: moduleName } = await import('module_name')" instead

Or maybe

ReferenceError: require is not defined in ES module scope, see the documentation for import here: ...

Or even (not directly referencing the import itself, leading users to have to go look at the docs!)

ReferenceError: require is not defined in ES module scope, you can use ES module styled dynamic imports instead

Which the user could interpret directly and make the change:

const { default: fetch } = await import("node-fetch");
(async function main() {
  const response = await fetch("https://httpbin.org/get");
  const json = await response.json();
  console.log(json);
})();
$ node index.js                                                                                                                                                                                                       
(node:86241) ExperimentalWarning: stream/web is an experimental feature. This feature could change at any time
(Use `node --trace-warnings ...` to show where the warning was created)
{
  args: {},
  headers: {
    Accept: '*/*',
    'Accept-Encoding': 'gzip,deflate,br',
    Host: 'httpbin.org',
    'User-Agent': 'node-fetch',
    'X-Amzn-Trace-Id': 'Root=1-6171395b-7b89119e02d2082a34e20d31'
  },
  origin: '103.62.49.195',
  url: 'https://httpbin.org/get'
}

What do you see instead?

No response

Additional information

Picked up from this twitter thread https://twitter.com/jsoverson/status/1450823245146599429

I couldn't see any mention of a specific issue being created from this.

Metadata

Metadata

Assignees

No one assigned

    Labels

    errorsIssues and PRs related to JavaScript errors originated in Node.js core.esmIssues and PRs related to the ECMAScript Modules implementation.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions