okikio / sharedworker

A small spec. compliant polyfill for SharedWorkers, it acts as a drop in replacement for normal Workers.
https://sharedworker.okikio.dev
MIT License
42 stars 5 forks source link

[BUG] Vite production builds doesn't recognise web worker #9

Open VeryStrongFingers opened 1 week ago

VeryStrongFingers commented 1 week ago

Preface I'm not sure whether this Is a bug with @okikio/sharedworker or Vite itself - thought it was best to report here firstly in case you've seen this before, or I'm doing something dumb.

Describe the bug Only seems to affect Vite production builds, development works without issue.

When the worker is created through your package (via import SharedWorker from "@okikio/sharedworker";) Vite doesn't seem to recognise the Worker/SharedWorker and it will be missing from the production build. Usually workers are chunked separately (i.e. have their own file), but it's just missing entirely.

I believe Vite expects Web Workers to be constructed in the application itself, not within a separate package (node_modules). https://v3.vitejs.dev/guide/features.html#web-workers

Versions Vite 5.4.11 (latest at time of posting) also tried older 5.3.* versions, same result

(I believe the usage of Vue & TypeScript is irrelevant here though) Vue 3.5.6 TypeScript 4.7.4

Additional context Seems that Vite does not recognise Web Workers that are constructed in a third-party package. I have been able to resolve this issue with these changes

package:

--- a/src/index.ts
+++ b/src/index.ts
@@ -7,19 +7,15 @@
 export const SharedWorkerSupported = "SharedWorker" in globalThis;

 /**
  * A polyfill class for `SharedWorker`, it accepts a URL/string as well as any other options the spec. allows for `SharedWorker`. It supports all the same methods and properties as the original, except it adds compatibility methods and properties for older browsers that don't support `SharedWorker`, so, it can switch to normal `Workers` instead. 
  */
 export class SharedWorkerPolyfill implements SharedWorker, EventTarget, AbstractWorker {
     /**
      * The actual worker that is used, depending on browser support it can be either a `SharedWorker` or a normal `Worker`.
      */
     public ActualWorker: SharedWorker | Worker;
-    constructor(url: string | URL, opts?: WorkerOptions) {
-        if (SharedWorkerSupported) {
-            this.ActualWorker = new SharedWorker(url, opts);
-        } else {
-            this.ActualWorker = new Worker(url, opts);
-        }
+    constructor(worker: SharedWorker | Worker) {
+        this.ActualWorker = worker;
     }

     /**

usage:

        let worker: SharedWorkerPolyfill;

        if (SharedWorkerSupported) {
            worker = new SharedWorkerPolyfill(new SharedWorker(new URL("./../worker.ts", import.meta.url), { name: "position-sync", type: "module" }));
        } else {
            worker = new SharedWorkerPolyfill(new Worker(new URL("./../worker.ts", import.meta.url), { name: "position-sync", type: "module" }));
        }

^the above code means the new Worker/SharedWorker is part of the application now and is realised by Vue during the build.

okikio commented 3 days ago

I'm so sorry I've been swamped this month, I've made the changes you've recommended as a new class called SharedWorkerPonyfill while still leaving SharedWorkerPolyfill with its original behaviour so as to avoid breaking changes. Please let me know what you think.