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: support for top level await? #2029

Closed
renhiyama opened this issue Oct 16, 2022 · 6 comments
Closed

🚀 Feature Request: support for top level await? #2029

renhiyama opened this issue Oct 16, 2022 · 6 comments
Labels
blocked Blocked on other work enhancement New feature or request

Comments

@renhiyama
Copy link

Describe the solution

Some libraries already use top level await. And I think you should allow this too. I dont see any problems with this, and if there is any, can be easily bypassed with an async function, but it harms code readability (dont want my whole file's code to go inside an async function). So can we please consider this?

 [ERROR] Build failed with 23 errors:

  ../imports/URLImport.js:4:11: ERROR: Top-level await is not available in the configured target
  environment ("es2020")
  ../imports/URLImport.js:5:24: ERROR: Top-level await is not available in the configured target
  environment ("es2020")
  ../imports/URLImport.js:6:9: ERROR: Top-level await is not available in the configured target
  environment ("es2020")
  ../imports/URLImport.js:9:19: ERROR: Top-level await is not available in the configured target
  environment ("es2020")
  ../imports/URLImportInstaller.js:4:9: ERROR: Top-level await is not available in the configured
  target environment ("es2020")
  ...


If you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new/choose
@renhiyama renhiyama added the enhancement New feature or request label Oct 16, 2022
@caass caass added the blocked Blocked on other work label Oct 16, 2022
@caass
Copy link
Contributor

caass commented Oct 16, 2022

There may be more ways to avoid using a top-level await within a worker -- for example, within a request handler, you can specify pass a promise to ctx.waitUntil. I understand, though, that this harms code readability as well.

There's an open issue with the bundler we use internally to support top-level await, and from skimming quickly it looks like while it would be technically possible for us to support TLA, the actual implementation is not ideal.

I'll keep this issue open for now as a way of tracking evanw/esbuild#253, so that once support is added in esbuild we can enable it within wrangler -- but given that the last update was about a year ago, I don't anticipate this being added any time soon.

@IgorMinar
Copy link
Contributor

I believe this error is misleading as the target environment mentioned in it refers to the esbuild config that is controlled internally in Wrangler and not configurable by the user.

I filed #2716 to update the target version. This doesn't make the top level await magically work, but it is possible to work because the workerd runtime doesn't support top-level awaits outside of a request context. There is however a workaround here, break up your worker and dynamically import a module with top level awaits from within a fetch handler:

main.ts:

export default {
  async fetch(request, environment, context) {
    const myWorker = (await import('./my-worker')).default;
    return myWorker.fetch(request, environment, context);
  }

my-worker.ts:

await Promise.resolve('yay, it works!');

export default {
  async fetch(request, environment, context) {
    ...
  }
}

This works (assuming patch for #2716) because the top level await is in an ES module that is dynamically imported from within a fetch handler.

Without the dynamic import, you'll get:

Error: Some functionality, such as asynchronous I/O, timeouts, and generating random values, can only be performed while handling a request.

@IgorMinar
Copy link
Contributor

hmm... the approach I proposed above might trigger "The script will never generate a response." error described in cloudflare/workerd#210 if the runtime is hit by two requests while awaiting the initialization.

@IgorMinar
Copy link
Contributor

I tried various things (especially using context.waitUntil) to make the top level await work, but nothing worked reliably, so I ended up resorting to the only thing that does seem to work reliably:

main.ts:

export default {
  async fetch(request, environment, context) {
    const myWorker = (await import('./my-worker')).default;
    return myWorker.fetch(request, environment, context);
  }

my-worker.ts:

const workerInit = Promise.resolve('yay, it works!');

export default {
  async fetch(request, environment, context) {
    await workerInit;
    ...
  }
}

@IgorMinar
Copy link
Contributor

I believe that this is now resolved with fix for #2716, there is still an issue related to cloudflare/workerd#389 and cloudflare/workerd#402 but those should be tracked separately.

@IgorMinar
Copy link
Contributor

to clarify, I verified that top-level await works as expected except for that odd issue with esbuild, which I think stems from awaiting WASM events.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
blocked Blocked on other work enhancement New feature or request
Projects
Archived in project
Development

No branches or pull requests

3 participants