2

I'm doing a small Node.js script, where I wanted to use:

in the same file. But I'm struggling on how to import both libraries at the same time.

If my type package.json type is commonJs:

  • I get SyntaxError: Cannot use import statement outside a module when trying to import import { loadJsonFile } from "load-json-file"
  • I get Error [ERR_REQUIRE_ESM]: require() of ES Module D:\Dev\my-project\node_modules\load-json-file\index.js from D:\Dev\fsvl-date-check\index.js not supported. Instead change the require of D:\Dev\my-project\node_modules\load-json-file\index.js in D:\Dev\my-project\index.js to a dynamic import() which is available in all CommonJS modules. if I try to load with require("load-json-file")().

Now if I try to switch my package.json to module:

  • I get SyntaxError: Named export 'prompt' not found. The requested module 'prompt-sync' is a CommonJS module, which may not support all module.exports as named exports. when I try to import like this: import { prompt } from "prompt-sync";.
  • I get ReferenceError: require is not defined in ES module scope, you can use import instead if I try to import it like this: var prompt = require("prompt-sync")();

How can I use both those packages in the same project?

jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
J4N
  • 19,480
  • 39
  • 187
  • 340

1 Answers1

4

From within a ES module ("type": "module"):

You want to do import prompt from 'prompt-sync';. While you can fully import commonjs modules from ES modules, there are no named exports. So you can only import the default export. Either of these lines work and do the same:

import { default as prompt} from 'prompt-sync';
import prompt from 'prompt-sync';

This is because an commonjs module has only one export.

From within a commonjs module

To import a ES module you need to do dynamic import, as stated by the error message:

const loadJsonFileModule = await import('load-json-file');

import() return a Promise, resolving to a module. So you need to call it from within an async function, or use .then to resolve the promise.

Then loadJsonFileModule is a module, wrapping all the exports, not the default export. So you will need to do something like loadJsonFileModule.loadJsonFile(...).

Lux
  • 17,835
  • 5
  • 43
  • 73
  • It appears that *prompt-sync* in particular [needs to be passed options](https://stackoverflow.com/a/29924193/1048572), so it would be `import makePrompt from 'prompt-sync'; const prompt = makePrompt(options);` – Bergi May 22 '23 at 13:07
  • II was not aware of the notion of `named` export, thanks! It works – J4N May 22 '23 at 13:25
  • 1
    "*there are no named exports, you can only import the default export.*" - this is not quite accurate. https://nodejs.org/api/esm.html#commonjs-namespaces: "*For better compatibility with existing usage in the JS ecosystem, Node.js in addition attempts to determine the CommonJS named exports of every imported CommonJS module to provide them as separate ES module exports using a static analysis process. […] The detection of named exports is based on common syntax patterns but does not always correctly detect named exports.*" – Bergi May 22 '23 at 13:31