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

DOMException when using web worker during dev with backend integration #13680

Open
7 tasks done
Arzaroth opened this issue Jun 29, 2023 · 10 comments
Open
7 tasks done

DOMException when using web worker during dev with backend integration #13680

Arzaroth opened this issue Jun 29, 2023 · 10 comments
Labels
feat: web workers has workaround p2-edge-case Bug, but has workaround or limited in scope (priority)

Comments

@Arzaroth
Copy link

Describe the bug

I am trying to use web workers in order to not clog the main thread (when computing hashes of large files for instance).

We have a backend so I'm using some kind a backend integration in dev mode. As such, for the assets to load properly we're going the "origin" approach (i.e., forcing server.origin be https://localhost:5173 in the vite config). I won't be able to go the "proxy route" as suggested in the documentation due to network constraints.

Using this, the assets load but when using web workers, I encounter the following error:

Uncaught (in promise) DOMException: Failed to construct 'Worker': Script at 'https://localhost:5173/src/utils/hash.worker.js?type=module&worker_file' cannot be accessed from origin 'https://app-dev.net'.
    at new WorkerWrapper (https://localhost:5173/src/utils/hash.worker.js?worker&inline:2:18)
    at ttt (https://localhost:5173/src/main.js:144:20)
    at https://localhost:5173/src/main.js:148:1

I understand why that's the case, but I have no idea as to what I can do to make it work. I tried adding CSP headers to no avail.
I know this can be circumvented by using a Blob URL and a raw import, but the code inside the worker has to be transpiled in my case since I'm doing some import there.

Everything works fine when built, I noticed it uses the "Blob trick" too, on the transpiled source.

Is there a way to mimic this in dev mode?

Reproduction

https://stackblitz.com/edit/vitejs-vite-hwpuck

Steps to reproduce

You won't able to reproduce in stackblitz but you can by downloading the code to run it locally.
Open 2 terminals : one for vite and the other one for the backend.
In the vite terminal, run npm install && npm run dev
In the backend terminal, run node server.js
Access the backend (http://localhost:8000). In the browser console, you'll see the error.

System Info

System:
    OS: Windows 10 10.0.22621
    CPU: (8) x64 AMD Ryzen 5 2400G with Radeon Vega Graphics
    Memory: 11.25 GB / 29.94 GB
  Binaries:
    Node: 20.1.0 - C:\Program Files\nodejs\node.EXE
    Yarn: 3.6.0 - C:\Program Files\nodejs\yarn.CMD
    npm: 6.14.17 - C:\Program Files\nodejs\npm.CMD
  Browsers:
    Chrome: 114.0.5735.199
    Edge: Spartan (44.22621.1848.0), Chromium (114.0.1823.55)
    Internet Explorer: 11.0.22621.1

Used Package Manager

yarn

Logs

No response

Validations

@stackblitz
Copy link

stackblitz bot commented Jun 29, 2023

Fix this issue in StackBlitz Codeflow Start a new pull request in StackBlitz Codeflow.

@sapphi-red
Copy link
Member

sapphi-red commented Nov 20, 2023

This is happening because Workers are always fetched with requestMode="same-origin" (whatwg/html#3656).

The current workaround is to use this constructor:

import workerUrl from './worker.js?worker&url'

const js = `import ${JSON.stringify(new URL(workerUrl, import.meta.url))}`
const blob = new Blob([js], { type: "application/javascript" })
function WorkaroundWorker(options) {
  const objURL = URL.createObjectURL(blob)
  const worker = new Worker(objURL, { type: "module", name: options?.name })
  worker.addEventListener("error", (e) => {
    URL.revokeObjectURL(objURL)
  })
  return worker;
}

related: whatwg/html#6911

@sapphi-red sapphi-red added the p2-edge-case Bug, but has workaround or limited in scope (priority) label Nov 20, 2023
@sapphi-red
Copy link
Member

It seems we cannot simply include the code above in Vite. This will change the baseURI (self.location.href) to be null.

@Arzaroth
Copy link
Author

Arzaroth commented Jan 9, 2024

Indeed the proposed workaround does work. When I tried the Blob trick I was doing it on the worker code itself, I hadn't considered doing it on an import statement instead. Pretty neat! I can even wrap it with Comlink.

I don't know if this warrants a change in Vite itself then. It all happens because I'm running dev mode for a library loaded by a backend on another URL, which seems to be a marginal use case.

Thanks.

@lk77
Copy link

lk77 commented Jan 29, 2024

@sapphi-red your workaround works ! thanks

@shubh46
Copy link

shubh46 commented May 6, 2024

@sapphi-red your workaround works ! thanks

Please, can I get an example how to use above workaround

@shubh46
Copy link

shubh46 commented May 6, 2024

This is happening because Workers are always fetched with requestMode="same-origin" (whatwg/html#3656). new Worker has credentials option, but IIUC it is disabled.

The current workaround is to use this constructor:

import workerUrl from './worker.js?worker&url'

const js = `import ${JSON.stringify(new URL(workerUrl, import.meta.url))}`
const blob = new Blob([js], { type: "application/javascript" })
function WorkaroundWorker(options) {
  const objURL = URL.createObjectURL(blob)
  const worker = new Worker(objURL, { type: "module", name: options?.name })
  worker.addEventListener("error", (e) => {
    URL.revokeObjectURL(objURL)
  })
  return worker;
}

please can we get an small example?

@boomsi
Copy link

boomsi commented May 20, 2024

This is happening because Workers are always fetched with requestMode="same-origin" (whatwg/html#3656). new Worker has credentials option, but IIUC it is disabled.

The current workaround is to use this constructor:

import workerUrl from './worker.js?worker&url'

const js = `import ${JSON.stringify(new URL(workerUrl, import.meta.url))}`
const blob = new Blob([js], { type: "application/javascript" })
function WorkaroundWorker(options) {
  const objURL = URL.createObjectURL(blob)
  const worker = new Worker(objURL, { type: "module", name: options?.name })
  worker.addEventListener("error", (e) => {
    URL.revokeObjectURL(objURL)
  })
  return worker;
}

Useful, thanks

@zakutnya
Copy link

zakutnya commented Aug 9, 2024

@shubh46

Please, can I get an example how to use above workaround

Monaco Editor + MySQL worker + Vite example:

// userWorker.ts

import workerUrl from "monaco-sql-languages/esm/languages/mysql/mysql.worker.js?worker&url";
//                 import the worker you need and don't forget about this tail ^^^^^^^^^

const js = `import ${JSON.stringify(new URL(workerUrl, import.meta.url))}`;
const blob = new Blob([js], { type: "application/javascript" });

function WorkaroundWorker([options](options: {name: string})) {
    const objURL = URL.createObjectURL(blob);
    const worker = new Worker(objURL, { type: "module", name: options?.name });
    worker.addEventListener("error", (e) => {
        URL.revokeObjectURL(objURL);
    });
    return worker;
}

self.MonacoEnvironment = {
    getWorker: function () {
        return WorkaroundWorker({ name: "mysql.worker" });
        //     ^^^^^^^ here's where the workaround is used
    },
};

@OskarAsplin-cf
Copy link

OskarAsplin-cf commented Oct 31, 2024

Thanks @sapphi-red! Made it work with workerpool like this:

import workerpool from 'workerpool';
import workerUrl from './worker.js?worker&url'

const js = `import ${JSON.stringify(new URL(workerUrl, import.meta.url))}`
const blob = new Blob([js], { type: "application/javascript" })
const objURL = URL.createObjectURL(blob)

const pool = workerpool.pool(objURL, { type: 'module' });

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feat: web workers has workaround p2-edge-case Bug, but has workaround or limited in scope (priority)
Projects
None yet
Development

No branches or pull requests

7 participants