As of webpack 5, you can use Web Workers without worker-loader.
new Worker(new URL('./worker.js', import.meta.url));
// or customize the chunk name with magic comments
// see https://webpack.js.org/api/module-methods/#magic-comments
new Worker(
/* webpackChunkName: "foo-worker" */ new URL('./worker.js', import.meta.url)
);
The syntax was chosen to allow running code without bundler, it is also available in native ECMAScript modules in the browser.
Note that while the Worker API suggests that Worker constructor would accept a string representing the URL of the script, in webpack 5 you can only use URL instead.
src/index.js
const worker = new Worker(new URL('./deep-thought.js', import.meta.url));
worker.postMessage({
question:
'The Answer to the Ultimate Question of Life, The Universe, and Everything.',
});
worker.onmessage = ({ data: { answer } }) => {
console.log(answer);
};
src/deep-thought.js
self.onmessage = ({ data: { question } }) => {
self.postMessage({
answer: 42,
});
};
When you set __webpack_public_path__ from a variable, and use publicPath equal to auto, worker chunks will get a separate runtime, and Webpack runtime will set publicPath to automatically calculated public path, that is probably is not what you expect.
To work around this issue, you need to set __webpack_public_path__ from within the worker code. Here is an example:
worker.js
self.onmessage = ({ data: { publicPath, ...otherData } }) => {
if (publicPath) {
__webpack_public_path__ = publicPath;
}
// rest of the worker code
}
app.js
const worker = new Worker(new URL('./worker.js', import.meta.url));
worker.postMessage({ publicPath: window.__MY_GLOBAL_PUBLIC_PATH_VAR__ });
Similar syntax is supported in Node.js (>= 12.17.0):
import { Worker } from 'worker_threads';
new Worker(new URL('./worker.js', import.meta.url));
Note that this is only available in ESM. Worker in CommonJS syntax is not supported by either webpack or Node.js.