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

Web workers in next.js fail with a ReferenceError #19996

Open
noe opened this issue Aug 8, 2023 · 3 comments
Open

Web workers in next.js fail with a ReferenceError #19996

noe opened this issue Aug 8, 2023 · 3 comments

Comments

@noe
Copy link

noe commented Aug 8, 2023

Version of emscripten/emsdk:

emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) 3.1.44-git
clang version 17.0.0 (https://github.com/llvm/llvm-project.git a8cbd27d1f238e104a5d5ca345d93bc1f4d4ab1f)
Target: wasm32-unknown-emscripten
Thread model: posix
InstalledDir: /usr/local/Cellar/emscripten/3.1.44/libexec/llvm/bin

Failing command line:

em++ \
  -v \
  --std=c++11 \
  -lembind \
  -s ENVIRONMENT='web,worker' \
  -sEXPORT_ES6 -s USE_ES6_IMPORT_META=0 \
  -sALLOW_MEMORY_GROWTH \
  -sMODULARIZE \
  --preload-file ... \

Explanation:

When using code generated by emscripten in a web worker under next.js with a preloaded file, the following error happens:

*****_worker.ts:51 Uncaught (in promise) ReferenceError: window is not defined
    at loadPackage (*****.js:55:19)
    at eval (*****.js:208:5)
    at eval (*****.js:210:3)

The generated piece of code that throws the error is the following:

(function() {
    // Do not attempt to redownload the virtual filesystem data when in a pthread or a Wasm Worker context.
    if (Module['ENVIRONMENT_IS_PTHREAD'] || Module['$ww']) return;
    var loadPackage = function(metadata) {

      var PACKAGE_PATH = '';
      if (typeof window === 'object') {
        PACKAGE_PATH = window['encodeURIComponent'](window.location.pathname.toString().substring(0, window.location.pathname.toString().lastIndexOf('/')) + '/');
      } else if (typeof process === 'undefined' && typeof location !== 'undefined') {
        // web worker
        PACKAGE_PATH = encodeURIComponent(location.pathname.toString().substring(0, location.pathname.toString().lastIndexOf('/')) + '/');
      }
      var PACKAGE_NAME = '*****.data';
      var REMOTE_PACKAGE_BASE = '*****.data';
...

The underlying problem seems to actually be in Next.js, under which in web wokers typeof window === 'object' is indeed true. See the discussion: vercel/next.js#39605

For now, I use a workaround in my web worker to set a fake window containing the functions used by emscripten:

    global.window = {
        encodeURIComponent: encodeURIComponent,
        location: location,
    };

I understand that the place to fix this is next.js, but I wanted to leave a trace here for people facing this problem. Please, feel free to close as wontfix.

@sbc100
Copy link
Collaborator

sbc100 commented Aug 8, 2023

Perhaps there is some more reliable way we can detect that we are running in a worker?

@kripken
Copy link
Member

kripken commented Aug 8, 2023

StackOverflow has the Emscripten code in the second answer for how to detect running in a worker 😆

https://stackoverflow.com/questions/7931182/reliably-detect-if-the-script-is-executing-in-a-web-worker

The first answer (checking for WorkerGlobalScope) might make sense? But it's possible there are exceptions to that as well...

@kripken
Copy link
Member

kripken commented Aug 8, 2023

Actually, maybe just reversing the order of our checks (first check for importScripts, and then window) might be an improvement. But, again, it might not be...

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

No branches or pull requests

3 participants