Skip to content

noVNC cannot be bundled due to top-level await in browser.js #1943

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

Open
mudge opened this issue Mar 13, 2025 · 11 comments · May be fixed by #1944
Open

noVNC cannot be bundled due to top-level await in browser.js #1943

mudge opened this issue Mar 13, 2025 · 11 comments · May be fixed by #1944

Comments

@mudge
Copy link

mudge commented Mar 13, 2025

Describe the bug
3677afe introduced a top-level await in lib/util/browser.js which prevents the library from being bundled with esbuild when previously it was fine.

To reproduce
Steps to reproduce the behavior:

  1. In a new directory, run npm install -S @novnc/novnc esbuild
  2. Create an index.js with import RFB from "@novnc/novnc";
  3. Attempt to bundle the file with npx esbuild index.js --bundle
  4. See errors like the following:
    ✘ [ERROR] This require call is not allowed because the imported file "node_modules/@novnc/novnc/lib/util/browser.js" contains a top-level await
    
        node_modules/@novnc/novnc/lib/rfb.js:11:23:
          11 │ var _browser = require("./util/browser.js");
             ╵                        ~~~~~~~~~~~~~~~~~~~
    
      The top-level await in "node_modules/@novnc/novnc/lib/util/browser.js" is here:
    
        node_modules/@novnc/novnc/lib/util/browser.js:179:68:
          179 │ exports.supportsWebCodecsH264Decode = supportsWebCodecsH264Decode = await _checkWebCodecsH264DecodeSupport();
              ╵                                                                     ~~~~~
    

Expected behavior
The file bundles successfully.

Server (please complete the following information):

  • noVNC version: 1.6.0
  • esbuild version: 0.25.1
  • Node version: v20.9.0
  • OS: macOS 15.3.1

Additional context
This happens even when using esbuild's default target of esnext. Is it possible to compile a version of browser.js that does not use a top-level await?

unode added a commit to embl-bio-it/jupyter-remote-desktop-proxy that referenced this issue Mar 13, 2025
The failure in 1.6.0 is due to the introduction of a top-level await
For more context refer to novnc/noVNC#1943
@SteveW94
Copy link

Sadly had to revert back to 1.5.0 also due to this issue :/

@CendioOssman
Copy link
Member

I don't think modules were designed with bundling in mind, so I suspect this will always be a bit shaky.

Bundling is also not something we've set out to explicitly support, so off the bat this would be an esbuild issue rather than a noVNC one. They seem to already be tracking it as evanw/esbuild#253.

As for not using top level awaits; that is not something we can commit to. Most web APIs are asynchronous. Using this construct allows us to avoid a lot of complexity and bugs.

I see you are using noVNC from npm, though. That is code that's been converted to CommonJS. What happens if you use the original noVNC code?

@SteveW94
Copy link

Hm I see...
Well it seems on the esbuild side, nothing has happend really for quite a long time there.
Regarding npm: Why is the code converted there? Are you suggesting to copy paste the plain code in our project? I can say that for any kind of production use we will have to rely on npm to keep automatic updates, license tracking etc etc. to work and wont copy static libs in.

So I guess the current question is, if there can be some kind of work around imagined, either possible from our side bundling it or from your side somehow.
I think at least from my projects perspective we would have to pin noVNC to 1.5.0 if not.

@CendioOssman
Copy link
Member

Regarding npm: Why is the code converted there?

Because npm is primarily the domain for Node.js, which uses CommonJS rather than "regular" JavaScript. Also, since noVNC is for the web and not Node.js, npm support has always been a very secondary priority for us.

I've seen that npm has grown support for ES modules, and some support for modules targeting the web. But it's not something anyone has investigated how that could be useful for noVNC.

Are you suggesting to copy paste the plain code in our project? I can say that for any kind of production use we will have to rely on npm to keep automatic updates, license tracking etc etc. to work and wont copy static libs in.

Yes, our primary distribution form is releases on GitHub. That is what we develop and test for.

So I guess the current question is, if there can be some kind of work around imagined, either possible from our side bundling it or from your side somehow.

The currently problematic line is only for H.264 support, which you likely don't need. So you could try patching it out.

If it works with our original code (rather than the CommonJS code in the npm package), then it could be worthwhile for someone to investigate npm's new support for ES modules.

@SteveW94
Copy link

I see, I will try if I can figure something out regarding the .H264 Support.

And on the side always learning sth new^^ As for me, "CommonJS" was always the synonym for "regular" basic Javascript and the standard to expect. Compared to that I considered this whole module-esm stuff as the the new fancy way which as you said coming slowly and might be (and is even already) supported to get loaded natively by the latest node-versions.

@elikoga
Copy link

elikoga commented Mar 14, 2025

I am experiencing a similiar problem when bundling using rollup, however it's error message is a bit clearer:

[commonjs--resolver] node_modules/@novnc/novnc/lib/util/browser.js (179:74): await isn't allowed in non-async function

Which tells us that the problem is that CommonJS files don't allow top-level-await. A quick look at https://babeljs.io/docs/babel-plugin-syntax-top-level-await tells us an issue:

Babel doesn't support transforming top-level await, but you can use Rollup's experimentalTopLevelAwait or webpack@5's experiments.topLevelAwait options.

So the root-cause/issue is the following: Babel fails to translate ES -> CJS top-level-awaits and downstream tooling complains that top-level-awaits are not allowed in CJS, even when translating CJS -> ES


I've seen that npm has grown support for ES modules, and some support for modules targeting the web. But it's not something anyone has investigated how that could be useful for noVNC.

I actually use noVNC for a browser client distributed through npm and was not aware of that, it worked so well before!

It looks like Node added support for ES Modules in Node 12 or so (see History), which can be enabled by setting "type":"module" in the package.json. Then, one can remove the CommonJS conversion step and distribute the same source package for both Node and Browsers. Since ESBuild already supports top-level await for ES Modules, fingers crossed 🤞, one can use NoVNC >=1.6.0 distributed via NPM in Browsers Processed with esbuild, just like before.

If it works with our original code (rather than the CommonJS code in the npm package), then it could be worthwhile for someone to investigate npm's new support for ES modules.

I will probably spend some time trying out some approaches to unblock Thymis-io/thymis#439 which broke due to the update.

martinpitt pushed a commit to cockpit-project/cockpit-machines that referenced this issue Mar 17, 2025
Bumps the esbuild group with 2 updates: [esbuild](https://github.com/evanw/esbuild) and [esbuild-wasm](https://github.com/evanw/esbuild).

Updates `esbuild` from 0.25.0 to 0.25.1
- [Release notes](https://github.com/evanw/esbuild/releases)
- [Changelog](https://github.com/evanw/esbuild/blob/main/CHANGELOG.md)
- [Commits](evanw/esbuild@v0.25.0...v0.25.1)

Updates `esbuild-wasm` from 0.25.0 to 0.25.1
- [Release notes](https://github.com/evanw/esbuild/releases)
- [Changelog](https://github.com/evanw/esbuild/blob/main/CHANGELOG.md)
- [Commits](evanw/esbuild@v0.25.0...v0.25.1)

---
updated-dependencies:
- dependency-name: esbuild
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: esbuild
- dependency-name: esbuild-wasm
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: esbuild
...

Signed-off-by: dependabot[bot] <[email protected]>

Pin novnc to 1.5.0 due to novnc/noVNC#1943
martinpitt pushed a commit to cockpit-project/cockpit-machines that referenced this issue Mar 17, 2025
Bumps the esbuild group with 2 updates: [esbuild](https://github.com/evanw/esbuild) and [esbuild-wasm](https://github.com/evanw/esbuild).

Updates `esbuild` from 0.25.0 to 0.25.1
- [Release notes](https://github.com/evanw/esbuild/releases)
- [Changelog](https://github.com/evanw/esbuild/blob/main/CHANGELOG.md)
- [Commits](evanw/esbuild@v0.25.0...v0.25.1)

Updates `esbuild-wasm` from 0.25.0 to 0.25.1
- [Release notes](https://github.com/evanw/esbuild/releases)
- [Changelog](https://github.com/evanw/esbuild/blob/main/CHANGELOG.md)
- [Commits](evanw/esbuild@v0.25.0...v0.25.1)

---
updated-dependencies:
- dependency-name: esbuild
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: esbuild
- dependency-name: esbuild-wasm
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: esbuild
...

Signed-off-by: dependabot[bot] <[email protected]>

Pin novnc to 1.5.0 due to novnc/noVNC#1943
@elikoga
Copy link

elikoga commented Mar 17, 2025

If it works with our original code (rather than the CommonJS code in the npm package), then it could be worthwhile for someone to investigate npm's new support for ES modules.

It works for me with ES Modules.

A PR has been opened that changes the published NPM Package to use ES Modules instead of shipping invalid CommonJS

@SteveW94
Copy link

Awesome! ☺️ Thanks for Bringing that forward!

@naggie
Copy link

naggie commented Mar 17, 2025

Thanks @elikoga this will save me a lot of hassle! :-)

@und3f
Copy link

und3f commented Apr 16, 2025

Thanks for working on that! I have same bundling problem and build from @elikoga's branch allowed to bundle noVNC successfully.

@elikoga
Copy link

elikoga commented Apr 16, 2025

I'll get back to updating the branch with current review changes soon

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

Successfully merging a pull request may close this issue.

6 participants