How can I import an ES module in the Node.js REPL in Node 8?
Asked Answered
C

5

95

I have an ES6 module right.mjs. Executing it as a parameter to node works well:

$ node --version
v8.10.0

$ node --experimental-modules right.mjs
(node:4492) ExperimentalWarning: The ESM module loader is experimental.
executing right module
`executing right module` is the output of the module.

In contrast to that, the following input in the REPL waits for further input:

$ node --experimental-modules
> (node:4526) ExperimentalWarning: The ESM module loader is experimental.

> import 'right.mjs';
...

I don't understand why.

The same with:

> import './right.mjs';
...

Trying to require results in:

> require('./right.mjs');
Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: /home/xxx/right.mjs
    at Object.Module._extensions..mjs (module.js:686:11)
    at Module.load (module.js:565:32)
    at tryModuleLoad (module.js:505:12)
    at Function.Module._load (module.js:497:3)
    at Module.require (module.js:596:17)
    at require (internal/module.js:11:18)

So, how can I import an ES module in the Node.js REPL?

Colvert answered 20/2, 2019 at 10:54 Comment(1)
There are REPLs out there which support modules, such as Replete.Mirisola
C
58

This is not currently possible. ES modules are supposed to be imported from the ES module scope, while REPL isn't considered one. This can improve with time because the support of ES modules is experimental. The use of require and import is mutually exclusive in the Node.js module implementation, and REPL already uses require.

Dynamic import is supported in the REPL since Node.js 13. With node --experimental-repl-await, it is:

await import('./right.mjs');
Cytolysin answered 20/2, 2019 at 11:45 Comment(6)
I believe this is now being tracked in github.com/nodejs/node/issues/33369Anhwei
REPL await is turned on by default as of Node 16.6, and has a different syntax for the feature flag.Plumbaginaceous
This needs to be updated. let { date } = await import('quasar') works fine in Node 18 without any flags.Mcniel
Except it's not a static import, so it's not "working fine".Barcellona
@BillerBuilder Can you clarify what's the problem with that? Top-level await is supported as well.Cytolysin
Being able to import ES modules only dynamically (and therefore asynchronously) within the scope of the current module is exactly how the current CJS handles ESM imports. Ergo the current REPL clearly runs in a CJS mode in some sort of async wrapper. Considering REPL is used mostly for checking synchronous code, this can lead to a different unexpected runtime behaviour.Barcellona
M
76

It is possible in Node.js v14, but you need to use the import function, rather than the import statement.

$ node

Welcome to Node.js v14.4.0.
Type ".help" for more information.
> let myModule;
undefined
> import("./my-module.js").then(module => { myModule = module });
Promise { <pending> }
> myModule.foo();
"bar"
Mirisola answered 3/9, 2020 at 8:36 Comment(5)
:( This looks like it still doesn't handle modules containing the export keywordChicken
@hallo it works for me with both named and default exports, but bear in mind you have to access the default export at module.default.Mirisola
Unfortunately, if your files contain imports that do not have the extension in the filename (`import something from './something';) as most projects do, it will error on you. Is there any way to fix this?Laux
The extension is now mandatory: nodejs.org/api/esm.html#esm_mandatory_file_extensions - I don't know of a way around that.Mirisola
The problem with asynchronous import is solved with node --experimental-repl-await. It's const myModule = await import("./my-module.js") then. An extension can be omitted with --experimental-specifier-resolution=node or custom loader (--experimental-loader).Cytolysin
C
58

This is not currently possible. ES modules are supposed to be imported from the ES module scope, while REPL isn't considered one. This can improve with time because the support of ES modules is experimental. The use of require and import is mutually exclusive in the Node.js module implementation, and REPL already uses require.

Dynamic import is supported in the REPL since Node.js 13. With node --experimental-repl-await, it is:

await import('./right.mjs');
Cytolysin answered 20/2, 2019 at 11:45 Comment(6)
I believe this is now being tracked in github.com/nodejs/node/issues/33369Anhwei
REPL await is turned on by default as of Node 16.6, and has a different syntax for the feature flag.Plumbaginaceous
This needs to be updated. let { date } = await import('quasar') works fine in Node 18 without any flags.Mcniel
Except it's not a static import, so it's not "working fine".Barcellona
@BillerBuilder Can you clarify what's the problem with that? Top-level await is supported as well.Cytolysin
Being able to import ES modules only dynamically (and therefore asynchronously) within the scope of the current module is exactly how the current CJS handles ESM imports. Ergo the current REPL clearly runs in a CJS mode in some sort of async wrapper. Considering REPL is used mostly for checking synchronous code, this can lead to a different unexpected runtime behaviour.Barcellona
T
45

With Node.js v16.9.1, which supports top level await, it's even simpler:

let { date } = await import('quasar') // module under node_modules, or your own one, etc.
date.getWeekOfYear(new Date())
Te answered 27/10, 2021 at 1:59 Comment(2)
This is the right answer for Node 18 as well. Should be the accepted answer now but the poster is essentially gone.Mcniel
For default imports: const { default: csv } = await import("csvtojson"); await csv().fromString('action,email\nsave,[email protected]') Chiron
P
12

It is not precisely what was asked about (not really REPL), but (using Node.js 12.6.0), it is possible to execute ESM code from the command line via --eval:

  1. First, if your ES modules have a .js extension instead of .mjs, put "type": "module" in file package.json (see Modules: ECMAScript modules, Enabling) to allow Node.js treating JavaScript files as modules
  2. Run node --experimental-modules --input-type=module --eval 'code here'

You could alias this as esmeval for example:

alias esmeval='node --experimental-modules --input-type=module --eval'

And then you can use it as:

esmeval 'import { method } from "./path/to/utils.js"; console.log(method("param"))'

If you can't use Node.js 12 yet as a primary version, but can install via nvm, make the alias point to the v12 installation:

alias esmeval='/c/software/nvm/v12.6.0/node.exe --experimental-modules --input-type=module --eval'

Pyknic answered 17/7, 2019 at 13:14 Comment(1)
Note that implementation of ES modules is changing with node 13 so this might not work in newer versions of node.Pyknic
A
0

Some googling on using a module in the REPL brought me here, and this is what worked for me:

npm install -g libphonenumber-js​
node​
> let lib = require('/opt/homebrew/lib/node_modules/libphonenumber-js')
> lib.isValidPhoneNumber('+97412345678')
false
> lib.isValidPhoneNumber('+15625551234')
true
Assignation answered 18/4, 2023 at 21:39 Comment(1)
As far as I can tell, this has nothing to do with ES modules. Since you are using a require, libphonenumber-js is loaded as a CJS module which is probably is (?). If I'm correct, this doesn't apply to this question concerning REPL + ESM.Muscat

© 2022 - 2024 — McMap. All rights reserved.