2

I'm using a loader package to which I pass the name of a loadee module and it require()s it.

The loader uses CJS's require() to dynamically require the loadee, but the loadee is an ES module. Because of this Node.js throws an error.

Error [ERR_REQUIRE_ESM]: require() of ES Module LOADEE from LOADER not supported.
Instead change the require of LOADEE in LOADER to a dynamic import() which is available in all CommonJS modules.

Neither the loader or the loadee are managed by me, so I can't modify them. I can't avoid using them either.

I can of course write an intermediary loadee, written in CJS (so the loader can load it), which then loads the true loadee and passes it back to the loader. But I don't know how to do it, since the dynamic import() is async (returns a promise), but the loader's require() is sync and expects the loaded module immediately.

Is there anything else I can do to make this thing work?

Example to show what's happening

In case the description I gave is not clear enough, I'm trying to post some minimal snippets of code to show what's happening:

LOADER (CJS; not written by me)
module.exports = function(pkg) {
  const x = require(pkg)
  console.log(x)
}
LOADEE (ES Module; not written by me)
default export const x = 1
./index.js (this one is mine: I can choose CJS or ES Module or anything else)
import load from 'LOADER'
load('LOADEE')

When I run node ./index.js this is what I get:

Error [ERR_REQUIRE_ESM]: require() of ES Module LOADEE from LOADER not supported.
Instead change the require of LOADEE in LOADER to a dynamic import() which is available in all CommonJS modules.

Similar questions

I already found similar questions on stack overflow. For instance:

They explain how to use import() to dynamically import a module. But that doesn't help me since I cannot change the require() call in the loader and don't know how to wrap it with an async dynamic import().

Is there anything I can do to make this thing work?

Blue Nebula
  • 932
  • 4
  • 9
  • I'd first say that the loader design you have is just not the right design for ESM modules since there is no dynamic and synchronous import. So, I think you're better off going back a few design steps and sharing why you got to the place you did where you're trying to do dynamic and synchronous imports. You probably need to replace that with a different design. But, you don't share any of that with us, so we can't really comment on a better architecture for the higher problem that your code is attempting to solve. – jfriend00 Dec 08 '21 at 04:17
  • @jfriend00: I have no control on the loader (nor on the loadee). It's a package my company uses and I can't replace it (not easily at least). I agree that it's a bad design, but what can I do? I'm looking for a workaround to get things to work again. – Blue Nebula Dec 08 '21 at 04:22
  • Well, that design is not compatible with ESM modules. So, I think you're going to have to question some assumptions/requirements you're being dealt. For a variety of reasons, synchronous loading of ESM modules is restricted to statically declared modules (not dynamic imports). As you seem to already know dynamic ESM imports are asynchronous. – jfriend00 Dec 08 '21 at 04:23
  • Yeah, I'm aware of that... Isn't there any secret flag to beg node to let me `require()` ESM? Or maybe as a last resort I can do something crazy like use some module-bundler to build the *loadee* into a CJS module? – Blue Nebula Dec 08 '21 at 04:28
  • No secrets I know of. See this [Node Modules at War: Why CommonJS and ES Modules Can’t Get Along](https://redfin.engineering/node-modules-at-war-why-commonjs-and-es-modules-cant-get-along-9617135eeca1) for a pretty detailed list of what you can and can't do. – jfriend00 Dec 08 '21 at 04:37
  • You cannot have a variable called `package` in your loader, that's a reserved keyword. Also does the function exported by the loader not return any value? – GOTO 0 Dec 08 '21 at 08:40
  • @GOTO0: I'm renaming the variable. This is not my actual code, I don't have a problem with any variable called package. It was a very minimal snippet to show what's happening. That's the same reason why the loader does nothing: there's no problem with the computation, but with `require()`. – Blue Nebula Dec 08 '21 at 18:50
  • @BlueNebula I mean, if the loader does not return a value, you won't be able to use the value `x = 1` exported by the loadee in your index.js. So do you need the loadee only for the side effects it produces when it gets evaluated? – GOTO 0 Dec 08 '21 at 19:00
  • 1
    @GOTO0: fine, I updated the example: now the *loader* is using the value the *loadee* exports. What I provided is a [Minimal, Reproducible Example](https://stackoverflow.com/help/minimal-reproducible-example) to show the issue. Tho *loader*, *loadee* and my code are actually more complicated than that, but the extra complication isn't relevant to the issue I'm facing. – Blue Nebula Dec 08 '21 at 20:21

0 Answers0