By default, when running in dev mode, Vite loads Web Worker script in module mode [1]. While this is compiled away in production build, it presents a problem if you’re developing with legacy web worker scripts that must run classic mode.

To work around this problem, you can import the web worker script as a string and run it using a Blob URL.

import workerString from './worker.js?raw';
const workerBlob = new Blob([workerString], {type: 'text/javascript'});
const workerURL = URL.createObjectURL(workerBlob);
const worker = new Worker(workerURL, {type: 'classic'});

EDIT (2021-07-23):

A previous version of this post used Data URL instead of Blob URL. Today I learned that Blob URLs are better suited for this task than Data URLs. This is because Blob URLs can only be created by the browser, which means that a web worker running from a Blob URL inherits the cross origin isolation settings from the top-level document.

Cross origin isolation is required to use advanced features like SharedArrayBuffer.

In comparison, Data URLs are can be generated by anyone, so they are not trusted. From MDN:

Note: Data URLs are treated as unique opaque origins by modern browsers, rather than inheriting the origin of the settings object responsible for the navigation.


  • [1] See this article for some background on module vs classic web workers.