standard-things / esm

Tomorrow's ECMAScript modules today!
Other
5.26k stars 146 forks source link

"Warning: require() of ES modules is not supported" when package.json has "type":"module" #855

Open yoursunny opened 4 years ago

yoursunny commented 4 years ago

Environment: Node 12.13.1, both Windows 10 and Ubuntu 16

Snippet to reproduce: package.json

{
  "dependencies": {
    "esm": "*"
  },
  "private": true,
  "type": "module"
}

module.js

export const X = 1;

main.cjs

require = require("esm")(module);
const m = require("./module.js");
console.log(m.X);

Steps to reproduce:

  1. Save the above three files in the same directory.
  2. npm install
  3. node main.cjs

Expected: console prints 1 and nothing else.

Actual:

$ node main.cjs
1
(node:8464) Warning: require() of ES modules is not supported.
require() of C:\Users\sunny\Documents\code\esmbug\module.js from C:\Users\sunny\Documents\code\esmbug\main.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 module.js to end in .cjs, change the requiring code to use import(), or remove "type": "module" from C:\Users\sunny\Documents\code\esmbug\package.json.

Observations:

fregante commented 4 years ago

This is a problem. Indeed v12.13.1 introduced a warning but in v13 it's an exception.

(node:40068) Warning: require() of ES modules is not supported.
require() of ./index.js from ./test/index.js 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 ./index.js to end in .cjs, change the requiring code to use import(), or remove "type": "module" from ./package.json.
  Uncaught exception in test/index.js

  Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: ./index.js
  ✖ test/index.js exited with a non-zero exit code: 1

  1 uncaught exception

I'm using esm via AVA

guybedford commented 4 years ago

Note that this error can be overridden by overwriting the require._extensions['.js'] function in Node.js. The same applies for the similar error when requiring .mjs files.

The body of the .js extension function is:

// Native extension for .js
Module._extensions['.js'] = function(module, filename) {
  if (filename.endsWith('.js')) {
    const pkg = readPackageScope(filename);
    // Function require shouldn't be used in ES modules.
    if (pkg && pkg.data && pkg.data.type === 'module') {
      const parentPath = module.parent && module.parent.filename;
      const packageJsonPath = path.resolve(pkg.path, 'package.json');
      throw new ERR_REQUIRE_ESM(filename, parentPath, packageJsonPath);
    }
  }
  const content = fs.readFileSync(filename, 'utf8');
  module._compile(content, filename);
};

which should be possible to replace in userland in this project with a version without the error.

Ensuring these were overidable was a goal here, so I hope this can solve the use case.

seanCodes commented 4 years ago

Note that this error can be overridden by overwriting the require._extensions['.js'] function in Node.js.

In case it’s not clear how to implement this 👆, like it was for me, you can use this (which is taken from @guybedford’s example on https://github.com/standard-things/esm/issues/868#issuecomment-594480715):

const module = require('module');
const fs = require('fs');
module.Module._extensions['.js'] = function (module, filename) {
  const contents = fs.readFileSync(filename, 'utf8');
  module._compile(require('fs').readFileSync(filename, 'utf8'), filename);
};

Essentially it’s just the native node code referenced above but without the error for require().

By putting this in your root module you should be able to get things working for node >= 12.13.1. 🙌

Note that there’s a PR (#877) to fix this, but the project seems stale so not sure if it will ever be merged. 😕

swetasrinaidu commented 2 years ago

Use axios instead of fetch.