Search code examples
javascriptwebpackwebpack-dev-serverweb-worker

How do you use Web Workers with Webpack 5?


I've been struggling to find the best way to use Web Workers while utilizing Webpack 5 and typescript. I try to follow the documentation, however, when I try to create a Web Worker, I am experiencing the following error:

Uncaught DOMException: Worker constructor: Failed to load worker script at "d:\Project\SeamCarving\js\dist0.bundle.js"

I am not sure why it is trying to access the file from my local system instead of through the development server like: http://localhost:8080/js/dist0.bundle.js.

Here's the code:

if (window.Worker) {
    let worker = new Worker(new URL("./image-worker", import.meta.url));

    worker.onmessage = function (message) {
      return receiveMessage(message);
    };

    worker.onerror = function (message) {
      console.log("ERROR: ", message.error);
      console.log(message.message, message.filename, message.lineno);
    };
}

webpack.config.js

const path = require('path');

module.exports = {
  entry: './js/main.ts',
  module: {
    rules: [
      {
        test: /\.ts$/,
        use: 'ts-loader',
        include: path.resolve(__dirname, 'js')
      }
    ]
  },
  resolve: {
    extensions: ['.ts', '.js']
  },
  devtool: 'source-map',
  mode: 'development',
  devServer: {
    contentBase: path.resolve(__dirname, './'),
    publicPath: path.resolve(__dirname, '/js/dist/'),
  },
  output: {
    publicPath: path.resolve(__dirname, "js/dist/"),
    filename: "bundle.js",
    path: path.resolve(__dirname, 'js/dist'),
  }
}

All resources I have found so far are using worker-loader, but it's my understanding Webpack 5 makes this obsolete.

View the full project on GitHub.


Solution

  • I figured out my problem,

    Incorrect output block:

    output: {
        publicPath: path.resolve(__dirname, "js/dist/"),
        filename: "bundle.js",
        path: path.resolve(__dirname, 'js/dist'),
    }
    

    publicPath in this case is set to use an absolute path. So, when I tried running it through the server it would serve as a file:// instead of through http://. Since Chrome (and I believe most modern browsers) don't allow you to load local files as scripts for security reasons, it was blocking it.

    Originally, I thought it may have been some sort of problem with using typescript, however, I learned it was just a misconfiguration causing the script to always use the absolute value.

    Corrected output block:

    output: {
        publicPath: "js/dist/",
        filename: "bundle.js",
        path: path.resolve(__dirname, 'js/dist'),
    }