12

Is top-level await still not supported in Node.js (Jan 2020, Node.js 13.5.0)?

I've tried some tutorials, like this one, but still no luck, always getting the same error:

D:\NodeJS>node --experimental-modules test.js
(node:17724) ExperimentalWarning: The ESM module loader is experimental.
file:///D:/NodeJS/test.js:9
await test();
^^^^^

SyntaxError: Unexpected reserved word

The entire file content:

function test() {
}

await test();

I have tried using "type": "module" in package.json, and renaming file into test.mjs, but still the same error, even with the latest Node.js 13.5.0

What am I doing wrong?

vitaly-t
  • 24,279
  • 15
  • 116
  • 138
  • top-level await is still a stage 3 proposal, what makes you think it's an experimental feature in node? – Klaycon Jan 03 '20 at 21:59
  • The article you refer to only talks about ES modules, not top level await – pietrovismara Jan 03 '20 at 22:01
  • that article describes enabling ES modules, which have been in the spec for a while, not top-level await which is still a proposal – Klaycon Jan 03 '20 at 22:01
  • @Klaycon As I explained, I did try renaming the file to `*.mjs`, and setting `type` to `module`, but none worked. Those things were supposed to turn the script into ES module. – vitaly-t Jan 03 '20 at 22:02
  • Then why is your question about top level await?? I think you are mixing up 2 separate topics. – pietrovismara Jan 03 '20 at 22:03
  • the script *is* an ES module. ES modules don't support top-level await yet, because adding top-level await to ES modules is still a stage 3 proposal and has not been implemented. – Klaycon Jan 03 '20 at 22:03
  • Guys, apologies, I just realized I clicked the ES module link and was providing the wrong link. [Here's the link I intended to provide](https://flaviocopes.com/javascript-await-top-level/). Updated the question also. – vitaly-t Jan 03 '20 at 22:05
  • @vitaly-t looking into it further, there aren't many resources, but i was able to find a flag that should work, please see my answer – Klaycon Jan 03 '20 at 22:12

5 Answers5

12

Per this issue tracker and this blog post, top-level await is available in Node v13.3+ behind the flag --harmony-top-level-await. The module flag you're enabling is only for ESM modules and not for top level await.

Klaycon
  • 10,599
  • 18
  • 35
  • That works, almost. [So that article is incorrect then](https://flaviocopes.com/javascript-await-top-level/)? Because it doesn't work, unless I use `mjs` file extension, or set `"type": "module"` inside `package.json`. – vitaly-t Jan 03 '20 at 22:16
  • @vitaly-t The article as well as the spec do state that top-level await will only work in ESM modules and never in commonjs modules, so you'll have to use the `mjs` extension or `"type": "module"` regardless. The article should mention that the feature is only in V8 behind that flag, but doesn't. It simply says it will "take some time" before it's available in node. – Klaycon Jan 03 '20 at 22:18
  • Also, when replacing that flag with just `--harmony`, nothing works then. – vitaly-t Jan 03 '20 at 22:19
  • 1
    Ah, my mistake then. I read elsewhere that `--harmony` enables all harmony flags. I've edited the answer. – Klaycon Jan 03 '20 at 22:20
  • 4
    I'm using Node v14.7.0 and I cannot find any `--harmony` flag in `node --help` but there is a `--experimental-repl-await` flag that does the trick for me. – Saeed Ahadian Aug 08 '20 at 13:54
  • exec `node --v8-options | grep await` and you can see `--harmony-top-level-await` – hankchiutw Jun 09 '22 at 02:39
4

node --experimental-repl-await works for the Node REPL

edit: the Node 16 REPL accepts top level await by default, you don't need the experimental flag anymore

Antoine Weber
  • 1,741
  • 1
  • 14
  • 14
  • 1
    Additionally, if you always want to have it enabled without explicitly passing the flag, you can `export NODE_OPTIONS='--experimental-repl-await'` in your `.bashrc` – jakub.g Mar 25 '21 at 21:07
2

I dont know why, but to get the --harmony features like you need to use --eval (-e) or --print (-p) instead of just launching node like node -e "import('./test.mjs')" --experimental-modules --input-type=module --harmony-top-level-await

file-content:

console.log(await Promise.resolve("test"));

console:

node -e "import('./test.mjs')" --experimental-modules --input-type=module --harmony-top-level-await
(node:9096) ExperimentalWarning: The ESM module loader is experimental.
test

MadProbe
  • 31
  • 4
  • 2
    As of `node 14.8.0` you now only need `--input-type=module`; the other two are enabled by default. – jakub.g Mar 25 '21 at 21:09
2

When using node -e:

Note that while top-level await is unflagged in node 14.8.0, when doing node -e (node --eval), the input type defaults to CJS, and top-level await is allowed only in ESM mode.

To tell that the input is ESM, you need a flag:

node --input-type=module -e 'console.log(await Promise.resolve(42))'
> 42
jakub.g
  • 38,512
  • 12
  • 92
  • 130
0

As an alternative, you could wrap your top level code into function mark it as async but don't wait for it's result. And only wait for the result of async action you need to wait.

That way you will have no warning, not work in 100% of situations, because top level code can be in multiple files etc. But for the majority hope could help, w/o need to change node flags, as it's not always easy (for example when you don't run any node commands yourself and need to extract some node/webpack configs)

setupApp()

async function setupApp () {
   await action1()
   action2()
}
Rantiev
  • 2,121
  • 2
  • 32
  • 56