Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature Request: Top level await #4028

Open
Banou26 opened this issue Jan 22, 2020 · 16 comments
Open

Feature Request: Top level await #4028

Banou26 opened this issue Jan 22, 2020 · 16 comments

Comments

@Banou26
Copy link
Contributor

Banou26 commented Jan 22, 2020

🙋 feature request

Parcel 2 could support Top Level Await.
Most bundlers/runtimes are starting to support it so it could be nice to have it in Parcel

Webpack's experiments.topLevelAwait experimental feature
Node stable support Node's(13.3+) --harmony-top-level-await/--harmony_top_level_await experimental feature
Deno's native support, denoland/deno#3212
Chromium's native support, https://bugs.chromium.org/p/v8/issues/detail?id=9344. Will ship in Chrome 89

@mischnic
Copy link
Member

(I think this is also needed for a true WASM-ESM integration, where the loading and compiling is inherently asynchronous).

https://github.com/tc39/proposal-top-level-await

Without scope hoisting, this seems easy enough (just await the require call).
Not sure if every async module needs to be wrapped with scope hoisting (and then await the init call), which would defy the benefits.

@Banou26
Copy link
Contributor Author

Banou26 commented Jan 23, 2020

For top level await while using scope hoisting, i think it'd only be possible for modules supported targets(https://github.com/babel/preset-modules) which also support top level await.

Just like you said wrapping async modules would just defy scope hoisting's benefits.

For this, parcel should bundle together static imports and split the others that are dynamically imported.

That's pretty much it, no ? Not sure about that.

@Banou26
Copy link
Contributor Author

Banou26 commented Aug 3, 2020

Node now officially supports top level await nodejs/node@54746bb 🎉

@mischnic
Copy link
Member

mischnic commented Aug 3, 2020

Maybe wrapping isn't even necessary?

// x.js
let v = await fetch(...);
export default "X:" + v;

// index.js
import x from "./x.js";
console.log(x);

->

(async function(){
var $x$var$v = await fetch(...);
var $x$export$default = "X:" + v;

console.log($x$export$default);
})()

Though I'm not sure how this should behave (or what browsers do/will do):

<script type="module" src="script-with-tla.js">
<script type="module" src="script-with-tla-2.js">

@Banou26
Copy link
Contributor Author

Banou26 commented Aug 4, 2020

I'm not sure what you what you mean by wrapping isn't necessary & then wrapping the scope hoisted code in a function.
Isn't one of the goals of scope hoisting to be able to use ESM's export declaration which needs to be top level, as explained nicely by Parcel 2's scope hoisting documentation:

– To generate a bundle that does ESM exports, the export declarations cannot be inside of functions.

Also, i tried searching for the specs that defines how scripts are executed but i couldn't really find anything so i ended up just using MDN's explanation of it.

The defer attribute has no effect on module scripts — they defer by default.
[...]
Scripts with the defer attribute will execute in the order in which they appear in the document.

@vsnthdev
Copy link

vsnthdev commented Dec 3, 2020

Looking for this amazing feature...

@aqzhyi
Copy link

aqzhyi commented Dec 5, 2020

Hello, the wonderful package. Any news about this how to get the top-level await to works?

@mischnic
Copy link
Member

mischnic commented Feb 3, 2021

@danieltroger #5761 (comment)

Two big problems with that:

  1. all modules (= imports) should be evaluated as parallel as possible
  2. With shared bundles, you still need to import something from another bundle, so something like await require() has to happen as well.

@danieltroger
Copy link
Contributor

all modules (= imports) should be evaluated as parallel as possible

Isn't that more of a next level feature? If they aren't now there's no downside of not doing it. It would just be a possibility to further improve once TLA is possible.

With shared bundles, you still need to import something from another bundle, so something like await require() has to happen as well.

Well I've never used shared bundles or require (I use import). But that's probably bad then and we users will have to continue wrapping our code into an async function ourselves :(

Thx for the info tho!

@avalanche1
Copy link

Gonna have to use good ol IIFEs then...
Otherwise won't compile with @parcel/optimizer-terser: Unexpected token: name $hoistedVarName$

@mischnic
Copy link
Member

Related:
https://twitter.com/bradleymeck/status/1506727720968986633
https://esm-exports-without-eval.glitch.me/

Details

the source code for c.mjs exports names: default, hi

// a.mjs
import './d.mjs';
import * as c from './c.mjs';
export function getNS() {
  return Object.getOwnPropertyNames(c);
}

// b.mjs
import {getNS} from './a.mjs';
console.log(getNS()); 
// Safari gets this right with TLA
// but V8 and SpiderMonkey incorrectly
// evaluate parents if using TLA and throwing errors
// FIXME: once V8 and SpiderMonkey allow TLA to block
//   graphs correctly move to `await new Promise` to
//   not fire off error alarms in devtools
throw getNS();
// await new Promise(()=>{})

// c.mjs
console.error('EVALUATING C, OH NO');
debugger;
export default 0;
export var hi;

// d.mjs
import './b.mjs';

@amatiasq
Copy link

amatiasq commented Mar 2, 2023

No update here?

@robclancy
Copy link

Awesome to see this isn't supported and the error isn't saying "hey we don't supports this feature we should have had 2 years ago"

@Volchunovich
Copy link

any updates guys?

@tdriley
Copy link

tdriley commented Jan 15, 2025

I'm using config-webextension and (as given as example in the docs) have set background.type as "module" in manifest.json along side the service worker entry point.

Now I need to make an await call first thing as soon as the service worker wakes (to use this package with MV3), but I get this error:

Uncaught SyntaxError: await is only valid in async functions and the top level bodies of modules.

That's because of this, right? Does parcel make the service worker not a module, even though that's specified in the manifest?

Update: Actually, yes, If I just look at the bundled manifest.json, I can see the type prop has been removed from the background object.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests