standard-things / esm

Tomorrow's ECMAScript modules today!
Other
5.27k stars 145 forks source link

Error [ERR_REQUIRE_ESM]: Must use import to load ES Module / require() of ES modules is not supported #868

Open chrisveness opened 4 years ago

chrisveness commented 4 years ago

I have suddenly started getting the following error:

$ npm test

> geodesy@2.2.0 test /home/travis/build/chrisveness/geodesy
> mocha --exit -r esm test/*.js

/home/travis/build/chrisveness/geodesy/node_modules/mocha/lib/mocha.js:1
Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: /home/travis/build/chrisveness/geodesy/test/dms-tests.js
require() of ES modules is not supported.
require() of /home/travis/build/chrisveness/geodesy/test/dms-tests.js from /home/travis/build/chrisveness/geodesy/node_modules/mocha/lib/mocha.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 dms-tests.js to end in .cjs, change the requiring code to use import(), or remove "type": "module" from /home/travis/build/chrisveness/geodesy/package.json.

    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1167:13)
    at /home/travis/build/chrisveness/geodesy/node_modules/mocha/lib/mocha.js:311:36
    at Array.forEach (<anonymous>)
    at Mocha.loadFiles (/home/travis/build/chrisveness/geodesy/node_modules/mocha/lib/mocha.js:308:14)
    at Mocha.run (/home/travis/build/chrisveness/geodesy/node_modules/mocha/lib/mocha.js:849:10)
    at Object.exports.singleRun (/home/travis/build/chrisveness/geodesy/node_modules/mocha/lib/cli/run-helpers.js:108:16)
    at exports.runMocha (/home/travis/build/chrisveness/geodesy/node_modules/mocha/lib/cli/run-helpers.js:143:13)
    at Object.exports.handler (/home/travis/build/chrisveness/geodesy/node_modules/mocha/lib/cli/run.js:305:3)
    at Object.runCommand (/home/travis/build/chrisveness/geodesy/node_modules/yargs/lib/command.js:242:26)
    at Object.parseArgs [as _parseArgs] (/home/travis/build/chrisveness/geodesy/node_modules/yargs/yargs.js:1087:28)
    at Object.parse (/home/travis/build/chrisveness/geodesy/node_modules/yargs/yargs.js:566:25)
    at Object.exports.main (/home/travis/build/chrisveness/geodesy/node_modules/mocha/lib/cli/cli.js:68:6)
    at Object.<anonymous> (/home/travis/build/chrisveness/geodesy/node_modules/mocha/lib/cli/cli.js:73:11)
    at Generator.next (<anonymous>)
    at internal/main/run_main_module.js:17:47 {
  code: 'ERR_REQUIRE_ESM'
}
npm ERR! Test failed.  See above for more details.

This doesn't make any sense, as I am not using require() anywhere at all.

It seems to be happening with Node.js > v12.12.0, including all v13.

Strangely, it seems that when I get this in my local environment, if I switch to 12.12.0 (using nvm), run tests, then switch back to later versions of Node, then all tests pass successfully (up to and including with v13.8.0).

However, I can't do this for the CI tests: travis-ci.org/chrisveness/geodesy/builds/649986393 (repo: github.com/chrisveness/geodesy.

Is there any way I can git CI tests to run successfully, as I can get local tests to run by switching versions of Node?

Thanks

azz commented 4 years ago

We've just hit this after pulling the latest node:12 docker images. I guess it is introduced in node 12.16.0

damianobarbati commented 4 years ago

What a mess, on node v12.16.0 all of my projects are now broken :)

This happens because I have in node_modules both:

@jdalton I guess ESM is transpiling both to require/cjs and nodejs is complaining about this because is enforcing the type=module + import syntax now.

EDIT: just reverted to node v12.1.14 where it shows the warning:

(node:7983) Warning: require() of ES modules is not supported.
uniqname commented 4 years ago

Ran into this problem, but for us, we tracked it down to @babel/runtime and this commit. Reverting to @babel/runtime@7.7.2 resolved the issue for us. It seems that the node v12 revamp of the native esm implementation to match node v13 triggered this, but the implications of this on this package (standard-things/esm) are not clear to me.

yoursunny commented 4 years ago

This is in fact the same bug as #855. It's an warning in Node 12.15 but becomes an error in Node 12.16.

guybedford commented 4 years ago

Which version of esm are you getting this error with?

iippis commented 4 years ago

Which version of esm are you getting this error with?

We are using 3.2.25

guybedford commented 4 years ago

Note this error is thrown by the .js extension handler in the CJS loader for Node.js here - https://github.com/nodejs/node/blob/master/lib/internal/modules/cjs/loader.js#L1211.

If someone wants to work on a PR to fix esm, the fix would be to patch the native extensions['.js'] with something like:

const module = require('module');
module.Module._extensions['.js'] = function(module, filename) {
  const content = fs.readFileSync(filename, 'utf8');
  module._compile(content, filename);
};
kriskowal commented 4 years ago

Would it be possible to switch the behaviors of importing with .js to either .cjs or .mjs depending on the type: module declaration in each package’s package.json?

glud123 commented 4 years ago

Ran into this problem, but for us, we tracked it down to @babel/runtime and this commit. Reverting to @babel/runtime@7.7.2 resolved the issue for us. It seems that the node v12 revamp of the native esm implementation to match node v13 triggered this, but the implications of this on this package (standard-things/esm) are not clear to me.

Thanks. Downgrade @babel/runtime to 7.7.2 fixed it for me.

seanCodes commented 4 years ago

I was able to get this working using the extension handler override solution above (thanks @guybedford!! 🙏) with a tweak to require('fs') since that was missing from the original snippet:

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);
};

or if you’re willing to sacrifice code clarity for something more condensed:

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

For purists, it’s worth mentioning that this can be used with ES module syntax too.

import { readFileSync } from 'fs';
import module from 'module';

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

Whatever you use, make sure to included it as early as possible in your app. (In my case it was a Vue/Nuxt app so I put it at the top of nuxt.config.js)

benbucksch commented 3 years ago

ping

I ran into this as well. I worked around it by removing type: module from packages.json of the imported package. It shouldn't have worked, but it did. Of course, that's the wrong solution, and won't help those using third-party packages.

Whatever the cause here is, the error message is flat out wrong, because there is no require().

mk-pmb commented 3 years ago

Thanks @guybedford and @seanCodes for your monkey patches. Unfortunately, in my case it just results in

Error: Cannot load module from .mjs: file:///mnt/…/node_modules/is-fn/index.js

albeit I assigend the loader function to both _extensions['.js'] and _extensions['.mjs']. Do you have an ideas what might be missing?

Venryx commented 3 years ago

Oh, it looks like Node 14.13.0+ supports named imports from common-js modules!: https://simonplend.com/node-js-now-supports-named-imports-from-commonjs-modules-but-what-does-that-mean

Well, some of them anyway. (the blog post linked shows how it only works for some packages -- ones where cjs-module-lexer is able to detect the export names through static analysis)

There may not be a need for these sorts of workarounds soon then. (I'll have to see, after using Node 14.13.0+ for a while)

seanCodes commented 3 years ago

@mk-pmb According to #851 this seems to be an esm limitation rather than node. The readme has a note:

🔒 .mjs files are limited to basic functionality without support for esm options.

It’s not clear what “basic functionality” is but I suspect that’s why the patch isn’t working in your case.

mk-pmb commented 3 years ago

Thanks for the idea. However I doubt that it's a problem with the esm module, because the same tarball extracted on an ancient Ubuntu with node v8.17.0 works, but breaks on Ubuntu focal with node v12.

That said, I don't understand what "without" means in the quote. Are esm files limited unless support is enabled in the options, or are they limited in that none of the options are supported? Then again, none of both interpretations would explain why it works on node v8.17.0.

diauweb commented 2 years ago

Concluding the discussion, this snippet shall work

https://gist.github.com/diauweb/f9f7be271ecc7bc0aecaf3dc891e18d2

mk-pmb commented 2 years ago

Thanks, I'll test it asap. Meanwhile I also found the fix-esm module.

mk-pmb commented 2 years ago

I think I understand the use case now. Your snippet and the fix-esm module both make it possible for a CJS module to synchronously require ESM modules. For that, they work. Thanks!

brumm commented 2 years ago

I made a reproduction case: https://stackblitz.com/edit/node-fyfxhz?file=main.js

yarn add esm file-icon; node index.js

importing path works, importing file-icon does not. This seems like a pretty big issue and makes it impossible to use esm at all for me.

jason-henriksen commented 2 years ago

I had a hell of a time with all this. I'm just posting my solution repo, in hopes it helps someone else.

This imports an ESM dependency (ora) into TypeScript without using babel. https://github.com/jason-henriksen/typescript-with-esm-no-babel-boilerplate

EarthlingDavey commented 2 years ago

I had a hell of a time with all this.

Oh snap 🤣 So happy to have come across your fork here! TY!

My issue was.. I needed @cfworker/json-schema (+ TS + testing) and spent hours going round in circles with mocha.

Your boilerplate made all my problems disapear 👊💯

Stusaw commented 2 years ago

I am constantly switching node versions (using nvm) to work on different projects. This was the root of my issue and needed to be on v14.0

devmuhammadnurulahsan commented 1 year ago

const random = require('random'); ^

Error [ERR_REQUIRE_ESM]: require() of ES Module F:\All Web Development World\Github-bot\node_modules\random\dist\random.module.js from F:\All Web Development World\Github-bot\index.js not supported. Instead change the require of random.module.js in F:\All Web Development World\Github-bot\index.js to a dynamic import() which is available in all CommonJS modules.

adembacajdev commented 1 year ago

Whoever wants to use both require and import, you only have to add these two lines at the top of your root project (index.js)

import {createRequire} from 'module';
const require = createRequire(import.meta.url);

and in package.json, you have to add

"type": "module"

Hope it works for you

mk-pmb commented 1 year ago

@adembacajdev Glad that it works for you. The problem is that declaring your package as type: module comes at a cost that lots of people don't want to pay.