-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
support for top level await #253
Comments
Sorry, top-level await is not supported. It messes with a lot of things and adding support for it is quite complicated. It likely won't be supported for a long time. |
Out of interest / for the issue history, is it possible to give some idea
of the sort of issues that arise here?
…On Sun, Jul 12, 2020 at 14:36 Erick Sosa Garcia ***@***.***> wrote:
Closed #253 <#253>.
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
<#253 (comment)>, or
unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAESFSS2NEUIRROFVJVY7GLR3IUGHANCNFSM4OX6XTIQ>
.
|
Right now there is an equivalence in esbuild between CommonJS modules and ES6 modules. A module can be written in either syntax and can even mix both syntaxes. That no longer works with CommonJS because the implementation of I'd like to punt this feature until later because there are already a lot of edge cases to work through with all of the features added so far (tree shaking, scope hoisting, code splitting, star re-exports, etc.) and this feature adds another dimension to the test case matrix. This feature is also lower priority for me than other features such as watch mode, plugins, finishing code splitting, and adding additional CSS and HTML file types, especially given that top-level await is a new feature and not yet widely used. Let's keep this issue open because I'm sure it'll come up again. At the very least esbuild should be able to parse top-level await and pass it through in non-bundling mode, which will be useful for people using esbuild as a transformer and not a bundler. I haven't added parsing support for top-level await yet because it's not clear exactly how to parse it. The way it works the JavaScript spec is that you're supposed to know beforehand whether the parsing goal is "script" or "module" and then only parse the TypeScript is another tool that does this so I've been waiting to see how they handle things. When I looked into this last they had a pretty severe bug so I'm going to wait a while longer for their implementation to settle before I consider how to approach this in esbuild. It looks like they still have open bugs on this such as this one, which interestingly appears to require a symbol table to parse correctly kind of like C. Not sure how I feel about that approach. Also, while I'm on the topic, apparently this feature also requires supporting top-level |
This was one of the major issues that the Node.js integration of ES modules had to deal with. The result was we did not permit CJS modules to load ES modules although bundlers like Webpack do. I believe previous dicussions here for eg Webpack have been around allowing
This was something else the Node.js modules integration had to carefully define with "type": "module" package.json boundaries. Mainly for the strict-mode-by-default handling for modules without module syntax, but also for other reasons like this too. I would avoid trying to follow anything TypeScript does personally as they have made it clear they will not lead the ecosystem but instead follow the winning conventions when they emerge. As such TypeScript is a typical friction point in modules workflows these days. One of the other implementation difficulties is that when bundling parallel dependencies, they are supposed to behave like a Promise.all, but in theory that is just a matter of wrapping. Definitely agreed this is a low priority, but thanks for the detailed explanation and for keeping this open for future reference, however long that might be. |
I'm planning to add pass-through support for this now that node is enabling it by default. It won't work while bundling but it will still be useful for certain use cases such as using esbuild as a library for converting TypeScript to JavaScript.
It looks like TypeScript's implementation ended up being to do an initial parse where top-level await is an identifier, then to reparse all expressions containing those identifiers as await expressions instead if the AST has an import or export statement. This approach isn't a good fit for esbuild's parser for many reasons including lack of a persistent token stream and the fact that parse errors are streamed in real-time and cannot be un-emitted. It's also a very complex approach because it may involve rewriting subsequent expressions (e.g. I've decided to just try unconditionally parsing the |
@evanw an added benefit is that TLA is only supported in the module goal and |
:( Is the situation for this still the same? |
Yes, top-level await still doesn't work with bundling. |
TLA is so complicated. I'm still trying to figure out how to support it but it has been really challenging. I'm trying to match all of the real evaluation order rules including parallel evaluation and microtask ordering while still doing scope hoisting and my attempts keep failing. I might need to undo some of esbuild's existing optimizations to get this in.
It would be amazing if that actually worked but joining together modules using promises causes things to evaluate in an incorrect order. I have written a TLA correctness fuzzer to verify that a TLA bundling strategy is correct by comparing it against V8, which I assume is correct. The only strategy that I've gotten to work is manually creating a module registry and using it to track which dependencies are remaining for each module. Presumably this is how the runtime works as well. But that's too much generated code size and run-time performance overhead for what I'm going for. I haven't quite gotten to the bottom of exactly what's so hard about this, but I have a hunch that the problem might be a fundamental difference between how the spec works and how promises work. I think it might be something like "the spec adds dependencies as modules are evaluated but the Promise API adds dependencies at the time .then() is called." I'm still investigating this. FWIW I couldn't get Webpack or SystemJS to match V8's behavior either. Does anyone know if there is a bundler-like implementation of TLA that is able to match V8's behavior? Also before I get even deeper into this, does anyone know if V8's behavior is incorrect somehow? |
Small update: It turns out that the top-level await specification and/or V8 have some subtle bugs that cause undesirable behavior. More details are here: evanw/tla-fuzzer#1. Many thanks to @sokra on the Webpack team for getting to the bottom of these issues. |
The newly-released version 0.10.0 has preliminary support for bundling with top-level await (previously top-level await was not allowed at all when bundling). From the release notes:
|
It works and this is awesome ! |
Hi, Into my project, I experimented an issue with a top-level await, on the Actually, esbuild still let some I solved it by adding a wrapper like Is there a reason to don't wrap the entire bundle, by default (or just if it have some top-level await)? If the project sources can help: https://glitch.com/edit/#!/immutable-isomorphic-demo?path=package.json%3A7%3A53 (The problematic |
Yes. Doing that would be incorrect. Top-level await is supposed to delay the evaluation of the importing module until the promise has been resolved, and the only way of doing that is to use a top-level await. In other words, top-level await cannot be polyfilled for environments that don't have it, at least as long as you support the possibility that the output file may be imported by something else. |
Ok for that, but since the ES modules aren't supported into a worker, the top-level await can't be supported. Maybe need a |
Ultimately top-level await will be supported with the |
Yes they are, in both worker and service worker. https://blog.chromium.org/2021/04/chrome-91-handwriting-recognition-webxr.html (look at bottom of the page)
|
Unsupported, actually, on Firefox ;) |
@ctjlewis when trying your suggestion:
I found |
Yeah, that flag is now called ESM target appropriately includes top-level await because ES Modules allow top-level await. Just saw your edit. I’m going to be running ESM through |
@ctjlewis Did you manage to get ESM working with pkg? I've been trying to get it to at least run via dynamic |
evanw/esbuild#253 Webpack is slow, but it seems to be full-featured.
evanw/esbuild#253 Webpack is slow, but it seems to be full-featured.
This is currently not possible, since esbuild has no support for top level await when bundling to cjs. See evanw/esbuild#253
If we use require() esbuild complains due to evanw/esbuild#253
If we use require() esbuild complains due to evanw/esbuild#253
If we use require() esbuild complains due to evanw/esbuild#253
If we use require() esbuild complains due to evanw/esbuild#253
If we use require() esbuild complains due to evanw/esbuild#253
If we use require() esbuild complains due to evanw/esbuild#253
This is currently not possible, since esbuild has no support for top level await when bundling to cjs. See evanw/esbuild#253
This is currently not possible, since esbuild has no support for top level await when bundling to cjs. See evanw/esbuild#253
I am currently working with deno which has top level support, is there any way to use esbuild with top level await?
The text was updated successfully, but these errors were encountered: