unjs/jiti

Top-level `await` is not supported

FloEdelmann opened this issue ยท 10 comments

In jiti v1.12.9 (via nuxt 2.15.8), top-level await doesn't seem to be supported, although it is in Node.js v14+.

See also https://v8.dev/features/top-level-await

When starting my Nuxt app (with top-level await in a server middleware ESM module), I get the following error:

 ERROR  ServerMiddleware Error: await is only valid in async function                                                                                                              21:52:20

  const schemas = await Promise.all([
  ^^^^^
  
  SyntaxError: await is only valid in async function
  at new Script (vm.js:102:7)
  at createScript (vm.js:262:10)
  at Object.runInThisContext (vm.js:310:10)
  at g (node_modules/jiti/dist/jiti.js:1:54973)
  at tests/fixture-valid.js:3:44
  at g (node_modules/jiti/dist/jiti.js:1:55111)
  at ui/api/routes/fixtures/from-editor.js:12:21
  at g (node_modules/jiti/dist/jiti.js:1:55111)
  at ui/api/routes.js:3:19
  at g (node_modules/jiti/dist/jiti.js:1:55111)
pi0 commented

Jiti works with CommonJS api (while top level await is an esm-only feature). Support is possible but might be tricky. In the meantime, use a main wrapper:

async function main() {
  // Move async logic here
}

main().catch(console.error)

As the world is (very slowly) moving more into esm, are there any plans on having jiti work with top-level await?

SST for example uses top-level await to load environment variables into the server. At least currently, trying to inject runtime config in Nuxt 3 using top-level await does not work and throws SyntaxError: await is only valid in async functions and the top level bodies of modules.

+1 for top-level await support. Tailwind is now using Jiti to load tailwind.config.mjs, but unfortunately, the choice to use Jiti also means that tailwind users can't leverage import.meta and can't use top-level await in tailwind config files.

pi0 commented

We are on it! This feature require a new API from jiti jiti.import(id) (which returns a promise unlike jiti(id) that returns a sync result and is blocker for top level await)

Very glad to hear it! Thanks a lot for the follow-up ๐Ÿคœ๐Ÿ’ฅ๐Ÿค›

Hi. Thanks for looking into this. Is there any update on progress?

Looking to work on this; @pi0 it seems to me that the main problem to solve is when a CommonJS module imports an ESM module with top-level await in it, because at that point the synchronous require is dependant on an async workload.

Reading through the code I see that jiti transpiles everything to CJS, why is that?
Wouldn't it be possible for ESM modules to stay ESM, unless required by a CJS module?

pi0 commented

Apart from all technical limitations that are beyond this feature for me to explain, sync API is important for jiti and libraries depend on it. ESM support with top level is on the plan but large scale migration is not that easy.

I assume that the goal is to support esm module importing through jiti.import, which must return a promise. Otherwise, if the plan is to allow top-level await in a module imported through jiti(...) that is not possible because you would need to synchronously wait for the module to asynchronously initialize.

pi0 commented

Top level support is now available in v2 (currently beta)