3

ES5 code can be run easily with Bash heredoc in terminal:

node <<HEREDOC
  var fs = require("fs");
  ...
HEREDOC

But ES6 code doesn't run, even with the correct --experimental-modules flag:

node --experimental-modules <<HEREDOC
  import fs from "fs";
  ...
HEREDOC

The error shown is:

(node:4130) ExperimentalWarning: The ESM module loader is experimental.
[stdin]:1
import fs from "fs";
       ^^

SyntaxError: Unexpected identifier
    at new Script (vm.js:83:7)
    at createScript (vm.js:267:10)
    at Proxy.runInThisContext (vm.js:319:10)
    at Object.<anonymous> ([stdin]-wrapper:6:22)
    at Module._compile (internal/modules/cjs/loader.js:722:30)
    at evalScript (internal/bootstrap/node.js:670:27)
    at ReadStream.<anonymous> (internal/bootstrap/node.js:340:15)
    at ReadStream.emit (events.js:187:15)
    at endReadableNT (_stream_readable.js:1098:12)
    at process.internalTickCallback (internal/process/next_tick.js:72:19)

It does show this info "ExperimentalWarning: The ESM module loader is experimental." which means Node.js is running correctly with ES6 module feature, however, the import keyword is just not working.

How to run ES6 code inline in terminal with Bash heredoc? I know I can write the code to file to load as ES6 module normally, but it's a short temporary code, should it be in heredoc better.

Dee
  • 7,455
  • 6
  • 36
  • 70
  • 1
    --experimental-modules doesn't support stdin modules (yet), it should do in Node 12. You could try using https://www.npmjs.com/package/esm if you really need to ES modules. – Jamesernator Apr 08 '19 at 07:58
  • @Jamesernator it does let me import built-in modules only, "npm i moment" doesn't work, "npm i -g moment" doesn't work too – Dee May 23 '19 at 07:36
  • 1
    Yeah only builtin modules work from stdin. There's an open issue for the same problem in the REPL, it's likely the same cause: https://github.com/nodejs/node/issues/19570 – Jamesernator May 24 '19 at 04:56

2 Answers2

3

Update:
Since Node.js 14, the flag --experimental-modules is no longer needed, it's already by default in Node.js for .mjs files, and also for heredoc, but the --input-type is still needed on CLI coz ES5 or ES6 is still supposed to be specified for the heredoc:

node --input-type module <<HEREDOC
  //example:
  import fs from "fs";
HEREDOC

Older guide:
After looking into it, Node 11 does not support ES modules from stdin at all, if you want to use modules in Node 11 you need to put them in a file.

With Node 12 (currently unreleased but you can try it using npm i -g node-nightly), you can use the flag --entry-type=module to use stdin as a module.

With node-nightly the following worked just fine:

node-nightly --experimental-modules --entry-type=module <<HEREDOC
  import fs from 'fs'
  console.log(fs);
HEREDOC

Edit:

As noted by @Jamesernator in comments, for node-nightly from v13, use "--input-type" instead of "--entry-type".

And only built-in modules are supported, ie. 'import' won't be able to find modules in local dir, and also won't be able to find global modules installed with '-g' flag. Related issue: https://github.com/nodejs/node/issues/19570

Dee
  • 7,455
  • 6
  • 36
  • 70
Jamesernator
  • 778
  • 7
  • 13
  • that node-nightly is superb! tks – Dee Apr 10 '19 at 10:40
  • but latest node-nightly now DOESN'T HAVE option "--entry-type" any more, checked just now with node-nightly v13.0.0-nightly2019042580c0b89bbb. It showed this error: bad option: --entry-type=module – Dee Apr 26 '19 at 06:17
  • 1
    It has been renamed --input-type a few days ago. You can just use Node 12 now though rather than nightly. – Jamesernator Apr 27 '19 at 07:48
  • 1
    It might still change though it's an ongoing discussion: https://github.com/nodejs/modules/issues/312 – Jamesernator Apr 27 '19 at 07:51
  • tks, i can use --input-type now, hope it won't change again. – Dee Apr 27 '19 at 08:39
  • it does let me import built-in modules only, "npm i moment" doesn't work, "npm i -g moment" doesn't work too – Dee May 23 '19 at 07:36
1

This is a great question that taught me a lot! Thanks for asking it. Here is what I learned:

First of all
Bash heredoc for node is like simply executing node and then typing whatever was typed in heredoc tag

I.E.

node --experimental-modules <<HEREDOC
  import fs from "fs";
  ...
HEREDOC

is equivalent to

node --experimental-modules
> import fs from "fs";

And executing node like that opens up the REPL from node

Secondly, the import syntax:

import fs from "fs"

There is no fs in "fs". That's not an issue for you now, but if the import went through, it wouldn't find that in the "fs" module. Instead, what would have been the correct syntax would be, for example:

import { readFile } from "fs";

This, however, yields:

SyntaxError: Unexpected token {

Lastly, the problem is that the entire feature is, indeed, experimental.

There are opened issues about this:

Adelin
  • 7,809
  • 5
  • 37
  • 65
  • Just a note in the Node implementation both `import fs from 'fs'` and `import * as fs from 'fs'` do the same thing, the default export for node builtin modules just exports the whole module back. – Jamesernator Apr 08 '19 at 08:16
  • @Adelin it does let me import built-in modules only, "npm i moment" doesn't work, "npm i -g moment" doesn't work too – Dee May 23 '19 at 07:37