Deno: Top-level for-await not working in bundles

Created on 1 Mar 2020  ·  17Comments  ·  Source: denoland/deno

Steps to reproduce

Create server.js with the following content:

import { serve } from "https://deno.land/[email protected]/http/server.ts";
const s = serve({ port: 8000 });
console.log("http://localhost:8000/");
for await (const req of s) {
  req.respond({ body: "Hello World\n" });
}

Run deno bundle server.js out.js

Run deno out.js

Expected result

The code runs

Actual result

error: Uncaught SyntaxError: Unexpected reserved word
► file:///path/to/out.js:113:17

113             for await (const req of s) {
                    ~~~~~

Notes

Adding await console.log("test"); or any other await statement is detected by the bundler and allows the for-await block to work properly. (See #4206)

deno 0.35.0
v8 8.1.310
typescript 3.8.2
bug cli upstream ☝️

Most helpful comment

would be good to change server example in the docs, because right now first code you run and do deno bundle yields you an error, code taken literally from section First steps

All 17 comments

Please read the typescript release notes : https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html#top-level-await

Top level avait only work for modules

@ecyrbe Thanks, however this is a module, and it does work correctly with a regular await. The issue is when using a for await (...) block which isn't detected by Deno in the same way other await statements are.

@davidbailey00 Can you append "in bundles" to the title?

Better repro:
a.js:

for await (const _ of []);
export {};

deno bundle a.js a.bundle.js && deno a.bundle.js:

Bundling "file:///mnt/c/Users/Nayeem/projects/deno/a.js"
Emitting bundle to "a.bundle.js"
2.3 kB emitted.
error: Uncaught SyntaxError: Unexpected reserved word
► file:///mnt/c/Users/Nayeem/projects/deno/a.bundle.js:107:17

107             for await (const _ of [])
                    ~~~~~

This may be an upstream bug with TypeScript - adding console.log(data); before line 49 in cli/js/compiler_api_test.ts shows that the execute function is missing async:

$ ./target/debug/deno bundle a.js a.bundle.js                                                                                         
Bundling "file:///Users/david/Code/Rust/deno/a.js"
System.register("a", [], function (exports_1, context_1) {
    "use strict";
    var __moduleName = context_1 && context_1.id;
    return {
        setters: [],
        execute: function () {
            for await (const _ of [])
                ;
        }
    };
});

Emitting bundle to "a.bundle.js"
2.3 kB emitted.

Top level for ... await is seperate in the standards process from Top level await. TypeScript has not implemented it, because it isn't progressed far enough in the standards. We are actually ignoring an error in the compiler that complains about it, because we can support it. So it is an upstream bug/limitation.

A work around for now would be to use a top level await in the module somewhere else, that would trigger TypeScript to emit the execute as an async function and everything else should work.

I was wrong, it is part of the Stage 3 proposal. I just got confused because it was implemented in V8 separately. The TypeScript implementation is incomplete and I have opened https://github.com/microsoft/TypeScript/issues/37402.

There is a PR open and pending review, which has been assigned. Hopefully it will get merged soon, but might not make TS 3.9.

I use Deno 1.0.0 with TS 3.9 and I can still reproduce this issue with the example above.

@StarpTech the issue is still open because the upstream bug is not fixed.

@kitsonk yes I saw it afterward. What's missing there? It looks like the PR is stale for 2 months.

🤷 I am not able to comment on why PRs are or are not merged in TypeScript.

try this hacking is work: change function=>async function

  execute: async function () {
        s = server_ts_2.serve({ port: 8000 });
        console.log("servce on http://localhost:8000");
        for await (const req of s) {
          req.respond({ body: "hhhhhh" });
        }
      },

@ZenLiuCN This is an upstream bug in TypeScript. We can not speed up TypeScript's development.

would be good to change server example in the docs, because right now first code you run and do deno bundle yields you an error, code taken literally from section First steps

Surrounding the for-await block with main function seems working around the problem.

import { serve } from "https://deno.land/[email protected]/http/server.ts";
const s = serve({ port: 8000 });
console.log("http://localhost:8000/");
async function main() {
  for await (const req of s) {
    req.respond({ body: "Hello World\n" });
  }
}
main()
$ deno bundle example.ts > bundle.js
Bundling file:///Users/kt3k/3/deno/ex.ts
$ deno run -A bundle.js 
http://localhost:8000/

Apologies if this has been discussed in the past, but Dart doesn't have top level code, instead it uses a main() function as an entry point, which can be marked as async. Would switching to this method be a viable solution?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

xueqingxiao picture xueqingxiao  ·  3Comments

JosephAkayesi picture JosephAkayesi  ·  3Comments

CruxCv picture CruxCv  ·  3Comments

justjavac picture justjavac  ·  3Comments

kyeotic picture kyeotic  ·  3Comments