14

I have a simple Web Worker which executes a initiates and handles messages from a websocket. The logic for the handler is imported from another module "MessageHandler". The reason for this is that the websockets rely on an external dependency (stompjs) anyway, and I would like to keep a single module with the message hangling logic for browsers which don't support webworkers.

import { connect, destroy } from "../src/utilities/MessageHandler";

onmessage = (message) => {
  const {type, value} = message.data;
  switch (type?.toLowerCase()) {
    case "connect":
      connect(value, message => postMessage(message))
      break;
    case "destroy":
      destroy();
      break;
  }
}

On the Dev server, this works fine, and I can place the file in the public folder, and start the Worker with:

  if (typeof Worker !== "undefined") {
    const workerUrl = new URL("/worker.js", import.meta.url);
    const worker = new Worker(workerUrl, {type:"module"});
    console.log(workerUrl);
    worker.postMessage({type:"connect", value: {...channelInfo}},);
    worker.onmessage = combineValues;
    onUnmounted(() => {
      worker.postMessage({type:"destroy"},);
      worker.terminate();
    })
  } else {
    console.log("Workers not allowed. Reverting to single threaded application.");
    connect(channelInfo, combineValues)
    onUnmounted(() => destroy())
  }

However when I build for production, the import from MessageHandler is not compiled into the worker file, and the program fails to execute. Is there a way to configure vite to bundle this web worker properly without having to manually copy all of the dependencies into the file, and does the WW file have to remain in the public folder? Bonus points if there is a way to do it using typescript for the Worker file instead of being forced back to JS.

2 Answers 2

26

While the accepted answer is working well, vite provides an easier way to import workers using query suffix ?worker.

Example:

import MyWorker from './worker?worker'

const worker = new MyWorker()

This is more useful for a number of reasons:

  • You don't need to put your worker script in public folder. Instead you can include it in src folder.
  • You can use aliases. For example if have @ pointing to src folder, so you do import MyWorker from '@/worker?worker'.
  • If you use typescript in your vue project, you can use a typescript worker as well without the need to compile it separately.

More info: https://vitejs.dev/guide/features.html#web-workers

Sign up to request clarification or add additional context in comments.

6 Comments

Trying this in Vite 5.1.4, it appears this works only if your web worker is JS, not TS. Might be a bug in Vite.
@JudahGabrielHimango trying now with Vite 5.2.0 and it is working also with TS. The answer set as accepted is not working for me at build time but only at runtime.
This seems to create a module worker (and you thus cannot use importScripts). Is there a way to use this syntax to create a classic worker?
How must one write the code inside the imported module? Can the imported module with ?worker be an ES module that exports something, or that at least can import? The documentation doesn't specify about the contents of the file.
@JoséRamírez You write like you would a regular web worker. developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/…
|
21

The way to do this is to import the worker like this

new Worker(
  new URL('./worker', import.meta.url),
  {type: 'module'}
);

where ./worker is not in the public folder but in the src folder like any other import.

See this section in the vite docs

3 Comments

I found in some cases, has to have the file extension added to it e.g. new URL('./file.js, import.meta.url) or else it would give weird MIME type errors
Testing this in Vite 5.1.4, this works but only if your web worker is JS, not TS.
note that this will simply copy the raw worker js file into the output assets directory. It will not transpile it (as with the rest of the code), so things like typescript doesn't work.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.